blob: c02ad70dafa7acea704fdf8b61a852e4748db2be [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>
22
Willy Tarreaua84d3742007-05-07 00:36:48 +020023/* List head of all known ACL keywords */
24static struct acl_kw_list acl_keywords = {
25 .list = LIST_HEAD_INIT(acl_keywords.list)
26};
27
28
Willy Tarreaua5909832007-06-17 20:40:25 +020029/*
30 * These functions are only used for debugging complex configurations.
Willy Tarreaua84d3742007-05-07 00:36:48 +020031 */
Willy Tarreaua5909832007-06-17 20:40:25 +020032
Willy Tarreau58393e12008-07-20 10:39:22 +020033/* force TRUE to be returned at the fetch level */
Willy Tarreaua5909832007-06-17 20:40:25 +020034static int
Willy Tarreau58393e12008-07-20 10:39:22 +020035acl_fetch_true(struct proxy *px, struct session *l4, void *l7, int dir,
36 struct acl_expr *expr, struct acl_test *test)
Willy Tarreaua5909832007-06-17 20:40:25 +020037{
Willy Tarreau58393e12008-07-20 10:39:22 +020038 test->flags |= ACL_TEST_F_SET_RES_PASS;
Willy Tarreaua5909832007-06-17 20:40:25 +020039 return 1;
40}
41
Willy Tarreaub6fb4202008-07-20 11:18:28 +020042/* wait for more data as long as possible, then return TRUE. This should be
43 * used with content inspection.
44 */
45static int
46acl_fetch_wait_end(struct proxy *px, struct session *l4, void *l7, int dir,
47 struct acl_expr *expr, struct acl_test *test)
48{
49 if (dir & ACL_PARTIAL) {
50 test->flags |= ACL_TEST_F_MAY_CHANGE;
51 return 0;
52 }
53 test->flags |= ACL_TEST_F_SET_RES_PASS;
54 return 1;
55}
56
Willy Tarreau58393e12008-07-20 10:39:22 +020057/* force FALSE to be returned at the fetch level */
Willy Tarreaua5909832007-06-17 20:40:25 +020058static int
Willy Tarreau58393e12008-07-20 10:39:22 +020059acl_fetch_false(struct proxy *px, struct session *l4, void *l7, int dir,
60 struct acl_expr *expr, struct acl_test *test)
Willy Tarreaua84d3742007-05-07 00:36:48 +020061{
Willy Tarreau58393e12008-07-20 10:39:22 +020062 test->flags |= ACL_TEST_F_SET_RES_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +020063 return 1;
64}
65
Willy Tarreau58393e12008-07-20 10:39:22 +020066
67/*
68 * These functions are exported and may be used by any other component.
69 */
70
71/* ignore the current line */
72int acl_parse_nothing(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreaua5909832007-06-17 20:40:25 +020073{
Willy Tarreau58393e12008-07-20 10:39:22 +020074 return 1;
75}
76
77/* always fake a data retrieval */
78int acl_fetch_nothing(struct proxy *px, struct session *l4, void *l7, int dir,
79 struct acl_expr *expr, struct acl_test *test)
80{
81 return 1;
Willy Tarreaua5909832007-06-17 20:40:25 +020082}
83
84/* always return false */
Willy Tarreau58393e12008-07-20 10:39:22 +020085int acl_match_nothing(struct acl_test *test, struct acl_pattern *pattern)
Willy Tarreaua5909832007-06-17 20:40:25 +020086{
Willy Tarreau11382812008-07-09 16:18:21 +020087 return ACL_PAT_FAIL;
Willy Tarreaua5909832007-06-17 20:40:25 +020088}
89
90
Willy Tarreaua84d3742007-05-07 00:36:48 +020091/* NB: For two strings to be identical, it is required that their lengths match */
92int acl_match_str(struct acl_test *test, struct acl_pattern *pattern)
93{
Willy Tarreauc8d7c962007-06-17 08:20:33 +020094 int icase;
95
Willy Tarreaua84d3742007-05-07 00:36:48 +020096 if (pattern->len != test->len)
Willy Tarreau11382812008-07-09 16:18:21 +020097 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +020098
99 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
100 if ((icase && strncasecmp(pattern->ptr.str, test->ptr, test->len) == 0) ||
101 (!icase && strncmp(pattern->ptr.str, test->ptr, test->len) == 0))
Willy Tarreau11382812008-07-09 16:18:21 +0200102 return ACL_PAT_PASS;
103 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200104}
105
Willy Tarreauf3d25982007-05-08 22:45:09 +0200106/* Executes a regex. It needs to change the data. If it is marked READ_ONLY
107 * then it will be allocated and duplicated in place so that others may use
108 * it later on. Note that this is embarrassing because we always try to avoid
109 * allocating memory at run time.
110 */
111int acl_match_reg(struct acl_test *test, struct acl_pattern *pattern)
112{
113 char old_char;
114 int ret;
115
116 if (unlikely(test->flags & ACL_TEST_F_READ_ONLY)) {
117 char *new_str;
118
119 new_str = calloc(1, test->len + 1);
120 if (!new_str)
Willy Tarreau11382812008-07-09 16:18:21 +0200121 return ACL_PAT_FAIL;
Willy Tarreauf3d25982007-05-08 22:45:09 +0200122
123 memcpy(new_str, test->ptr, test->len);
124 new_str[test->len] = 0;
125 if (test->flags & ACL_TEST_F_MUST_FREE)
126 free(test->ptr);
127 test->ptr = new_str;
128 test->flags |= ACL_TEST_F_MUST_FREE;
129 test->flags &= ~ACL_TEST_F_READ_ONLY;
130 }
131
132 old_char = test->ptr[test->len];
133 test->ptr[test->len] = 0;
134
135 if (regexec(pattern->ptr.reg, test->ptr, 0, NULL, 0) == 0)
Willy Tarreau11382812008-07-09 16:18:21 +0200136 ret = ACL_PAT_PASS;
Willy Tarreauf3d25982007-05-08 22:45:09 +0200137 else
Willy Tarreau11382812008-07-09 16:18:21 +0200138 ret = ACL_PAT_FAIL;
Willy Tarreauf3d25982007-05-08 22:45:09 +0200139
140 test->ptr[test->len] = old_char;
141 return ret;
142}
143
Willy Tarreaua84d3742007-05-07 00:36:48 +0200144/* Checks that the pattern matches the beginning of the tested string. */
145int acl_match_beg(struct acl_test *test, struct acl_pattern *pattern)
146{
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200147 int icase;
148
Willy Tarreaua84d3742007-05-07 00:36:48 +0200149 if (pattern->len > test->len)
Willy Tarreau11382812008-07-09 16:18:21 +0200150 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200151
152 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
153 if ((icase && strncasecmp(pattern->ptr.str, test->ptr, pattern->len) != 0) ||
154 (!icase && strncmp(pattern->ptr.str, test->ptr, pattern->len) != 0))
Willy Tarreau11382812008-07-09 16:18:21 +0200155 return ACL_PAT_FAIL;
156 return ACL_PAT_PASS;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200157}
158
159/* Checks that the pattern matches the end of the tested string. */
160int acl_match_end(struct acl_test *test, struct acl_pattern *pattern)
161{
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200162 int icase;
163
Willy Tarreaua84d3742007-05-07 00:36:48 +0200164 if (pattern->len > test->len)
Willy Tarreau11382812008-07-09 16:18:21 +0200165 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200166 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
167 if ((icase && strncasecmp(pattern->ptr.str, test->ptr + test->len - pattern->len, pattern->len) != 0) ||
168 (!icase && strncmp(pattern->ptr.str, test->ptr + test->len - pattern->len, pattern->len) != 0))
Willy Tarreau11382812008-07-09 16:18:21 +0200169 return ACL_PAT_FAIL;
170 return ACL_PAT_PASS;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200171}
172
173/* Checks that the pattern is included inside the tested string.
174 * NB: Suboptimal, should be rewritten using a Boyer-Moore method.
175 */
176int acl_match_sub(struct acl_test *test, struct acl_pattern *pattern)
177{
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200178 int icase;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200179 char *end;
180 char *c;
181
182 if (pattern->len > test->len)
Willy Tarreau11382812008-07-09 16:18:21 +0200183 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200184
185 end = test->ptr + test->len - pattern->len;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200186 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
187 if (icase) {
188 for (c = test->ptr; c <= end; c++) {
189 if (tolower(*c) != tolower(*pattern->ptr.str))
190 continue;
191 if (strncasecmp(pattern->ptr.str, c, pattern->len) == 0)
Willy Tarreau11382812008-07-09 16:18:21 +0200192 return ACL_PAT_PASS;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200193 }
194 } else {
195 for (c = test->ptr; c <= end; c++) {
196 if (*c != *pattern->ptr.str)
197 continue;
198 if (strncmp(pattern->ptr.str, c, pattern->len) == 0)
Willy Tarreau11382812008-07-09 16:18:21 +0200199 return ACL_PAT_PASS;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200200 }
Willy Tarreaua84d3742007-05-07 00:36:48 +0200201 }
Willy Tarreau11382812008-07-09 16:18:21 +0200202 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200203}
204
205/* This one is used by other real functions. It checks that the pattern is
206 * included inside the tested string, but enclosed between the specified
207 * delimitor, or a '/' or a '?' or at the beginning or end of the string.
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200208 * The delimitor is stripped at the beginning or end of the pattern.
Willy Tarreaua84d3742007-05-07 00:36:48 +0200209 */
210static int match_word(struct acl_test *test, struct acl_pattern *pattern, char delim)
211{
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200212 int may_match, icase;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200213 char *c, *end;
214 char *ps;
215 int pl;
216
217 pl = pattern->len;
218 ps = pattern->ptr.str;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200219 while (pl > 0 && (*ps == delim || *ps == '/' || *ps == '?')) {
Willy Tarreaua84d3742007-05-07 00:36:48 +0200220 pl--;
221 ps++;
222 }
223
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200224 while (pl > 0 &&
225 (ps[pl - 1] == delim || ps[pl - 1] == '/' || ps[pl - 1] == '?'))
Willy Tarreaua84d3742007-05-07 00:36:48 +0200226 pl--;
227
228 if (pl > test->len)
Willy Tarreau11382812008-07-09 16:18:21 +0200229 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200230
231 may_match = 1;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200232 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200233 end = test->ptr + test->len - pl;
234 for (c = test->ptr; c <= end; c++) {
235 if (*c == '/' || *c == delim || *c == '?') {
236 may_match = 1;
237 continue;
238 }
Willy Tarreaua84d3742007-05-07 00:36:48 +0200239
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200240 if (!may_match)
241 continue;
242
243 if (icase) {
244 if ((tolower(*c) == tolower(*ps)) &&
245 (strncasecmp(ps, c, pl) == 0) &&
246 (c == end || c[pl] == '/' || c[pl] == delim || c[pl] == '?'))
Willy Tarreau11382812008-07-09 16:18:21 +0200247 return ACL_PAT_PASS;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200248 } else {
249 if ((*c == *ps) &&
250 (strncmp(ps, c, pl) == 0) &&
251 (c == end || c[pl] == '/' || c[pl] == delim || c[pl] == '?'))
Willy Tarreau11382812008-07-09 16:18:21 +0200252 return ACL_PAT_PASS;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200253 }
Willy Tarreaua84d3742007-05-07 00:36:48 +0200254 may_match = 0;
255 }
Willy Tarreau11382812008-07-09 16:18:21 +0200256 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200257}
258
259/* Checks that the pattern is included inside the tested string, but enclosed
260 * between slashes or at the beginning or end of the string. Slashes at the
261 * beginning or end of the pattern are ignored.
262 */
263int acl_match_dir(struct acl_test *test, struct acl_pattern *pattern)
264{
265 return match_word(test, pattern, '/');
266}
267
268/* Checks that the pattern is included inside the tested string, but enclosed
269 * between dots or at the beginning or end of the string. Dots at the beginning
270 * or end of the pattern are ignored.
271 */
272int acl_match_dom(struct acl_test *test, struct acl_pattern *pattern)
273{
274 return match_word(test, pattern, '.');
275}
276
277/* Checks that the integer in <test> is included between min and max */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200278int acl_match_int(struct acl_test *test, struct acl_pattern *pattern)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200279{
Willy Tarreauae8b7962007-06-09 23:10:04 +0200280 if ((!pattern->val.range.min_set || pattern->val.range.min <= test->i) &&
281 (!pattern->val.range.max_set || test->i <= pattern->val.range.max))
Willy Tarreau11382812008-07-09 16:18:21 +0200282 return ACL_PAT_PASS;
283 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200284}
285
Willy Tarreaua67fad92007-05-08 19:50:09 +0200286int acl_match_ip(struct acl_test *test, struct acl_pattern *pattern)
287{
288 struct in_addr *s;
289
290 if (test->i != AF_INET)
Willy Tarreau11382812008-07-09 16:18:21 +0200291 return ACL_PAT_FAIL;
Willy Tarreaua67fad92007-05-08 19:50:09 +0200292
293 s = (void *)test->ptr;
294 if (((s->s_addr ^ pattern->val.ipv4.addr.s_addr) & pattern->val.ipv4.mask.s_addr) == 0)
Willy Tarreau11382812008-07-09 16:18:21 +0200295 return ACL_PAT_PASS;
296 return ACL_PAT_FAIL;
Willy Tarreaua67fad92007-05-08 19:50:09 +0200297}
298
Willy Tarreaua84d3742007-05-07 00:36:48 +0200299/* Parse a string. It is allocated and duplicated. */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200300int acl_parse_str(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200301{
302 int len;
303
Willy Tarreauae8b7962007-06-09 23:10:04 +0200304 len = strlen(*text);
305 pattern->ptr.str = strdup(*text);
Willy Tarreaua84d3742007-05-07 00:36:48 +0200306 if (!pattern->ptr.str)
307 return 0;
308 pattern->len = len;
309 return 1;
310}
311
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +0200312/* Free data allocated by acl_parse_reg */
313static void acl_free_reg(void *ptr) {
314
315 regfree((regex_t *)ptr);
316}
317
Willy Tarreauf3d25982007-05-08 22:45:09 +0200318/* Parse a regex. It is allocated. */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200319int acl_parse_reg(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreauf3d25982007-05-08 22:45:09 +0200320{
321 regex_t *preg;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200322 int icase;
Willy Tarreauf3d25982007-05-08 22:45:09 +0200323
324 preg = calloc(1, sizeof(regex_t));
325
326 if (!preg)
327 return 0;
328
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200329 icase = (pattern->flags & ACL_PAT_F_IGNORE_CASE) ? REG_ICASE : 0;
330 if (regcomp(preg, *text, REG_EXTENDED | REG_NOSUB | icase) != 0) {
Willy Tarreauf3d25982007-05-08 22:45:09 +0200331 free(preg);
332 return 0;
333 }
334
335 pattern->ptr.reg = preg;
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +0200336 pattern->freeptrbuf = &acl_free_reg;
Willy Tarreauf3d25982007-05-08 22:45:09 +0200337 return 1;
338}
339
Willy Tarreauae8b7962007-06-09 23:10:04 +0200340/* Parse a range of positive integers delimited by either ':' or '-'. If only
341 * one integer is read, it is set as both min and max. An operator may be
342 * specified as the prefix, among this list of 5 :
343 *
344 * 0:eq, 1:gt, 2:ge, 3:lt, 4:le
345 *
346 * The default operator is "eq". It supports range matching. Ranges are
347 * rejected for other operators. The operator may be changed at any time.
348 * The operator is stored in the 'opaque' argument.
349 *
Willy Tarreaua84d3742007-05-07 00:36:48 +0200350 */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200351int acl_parse_int(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200352{
Willy Tarreauae8b7962007-06-09 23:10:04 +0200353 signed long long i;
354 unsigned int j, last, skip = 0;
355 const char *ptr = *text;
356
357
Willy Tarreau8f8e6452007-06-17 21:51:38 +0200358 while (!isdigit((unsigned char)*ptr)) {
Willy Tarreauae8b7962007-06-09 23:10:04 +0200359 if (strcmp(ptr, "eq") == 0) *opaque = 0;
360 else if (strcmp(ptr, "gt") == 0) *opaque = 1;
361 else if (strcmp(ptr, "ge") == 0) *opaque = 2;
362 else if (strcmp(ptr, "lt") == 0) *opaque = 3;
363 else if (strcmp(ptr, "le") == 0) *opaque = 4;
364 else
365 return 0;
366
367 skip++;
368 ptr = text[skip];
369 }
Willy Tarreaua84d3742007-05-07 00:36:48 +0200370
371 last = i = 0;
372 while (1) {
Willy Tarreauae8b7962007-06-09 23:10:04 +0200373 j = *ptr++;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200374 if ((j == '-' || j == ':') && !last) {
375 last++;
376 pattern->val.range.min = i;
377 i = 0;
378 continue;
379 }
380 j -= '0';
381 if (j > 9)
382 // also catches the terminating zero
383 break;
384 i *= 10;
385 i += j;
386 }
Willy Tarreauae8b7962007-06-09 23:10:04 +0200387
388 if (last && *opaque >= 1 && *opaque <= 4)
389 /* having a range with a min or a max is absurd */
390 return 0;
391
Willy Tarreaua84d3742007-05-07 00:36:48 +0200392 if (!last)
393 pattern->val.range.min = i;
394 pattern->val.range.max = i;
Willy Tarreauae8b7962007-06-09 23:10:04 +0200395
396 switch (*opaque) {
397 case 0: /* eq */
398 pattern->val.range.min_set = 1;
399 pattern->val.range.max_set = 1;
400 break;
401 case 1: /* gt */
402 pattern->val.range.min++; /* gt = ge + 1 */
403 case 2: /* ge */
404 pattern->val.range.min_set = 1;
405 pattern->val.range.max_set = 0;
406 break;
407 case 3: /* lt */
408 pattern->val.range.max--; /* lt = le - 1 */
409 case 4: /* le */
410 pattern->val.range.min_set = 0;
411 pattern->val.range.max_set = 1;
412 break;
413 }
414 return skip + 1;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200415}
416
Willy Tarreau4a26d2f2008-07-15 16:05:33 +0200417/* Parse a range of positive 2-component versions delimited by either ':' or
418 * '-'. The version consists in a major and a minor, both of which must be
419 * smaller than 65536, because internally they will be represented as a 32-bit
420 * integer.
421 * If only one version is read, it is set as both min and max. Just like for
422 * pure integers, an operator may be specified as the prefix, among this list
423 * of 5 :
424 *
425 * 0:eq, 1:gt, 2:ge, 3:lt, 4:le
426 *
427 * The default operator is "eq". It supports range matching. Ranges are
428 * rejected for other operators. The operator may be changed at any time.
429 * The operator is stored in the 'opaque' argument. This allows constructs
430 * such as the following one :
431 *
432 * acl obsolete_ssl ssl_req_proto lt 3
433 * acl unsupported_ssl ssl_req_proto gt 3.1
434 * acl valid_ssl ssl_req_proto 3.0-3.1
435 *
436 */
437int acl_parse_dotted_ver(const char **text, struct acl_pattern *pattern, int *opaque)
438{
439 signed long long i;
440 unsigned int j, last, skip = 0;
441 const char *ptr = *text;
442
443
444 while (!isdigit((unsigned char)*ptr)) {
445 if (strcmp(ptr, "eq") == 0) *opaque = 0;
446 else if (strcmp(ptr, "gt") == 0) *opaque = 1;
447 else if (strcmp(ptr, "ge") == 0) *opaque = 2;
448 else if (strcmp(ptr, "lt") == 0) *opaque = 3;
449 else if (strcmp(ptr, "le") == 0) *opaque = 4;
450 else
451 return 0;
452
453 skip++;
454 ptr = text[skip];
455 }
456
457 last = i = 0;
458 while (1) {
459 j = *ptr++;
460 if (j == '.') {
461 /* minor part */
462 if (i >= 65536)
463 return 0;
464 i <<= 16;
465 continue;
466 }
467 if ((j == '-' || j == ':') && !last) {
468 last++;
469 if (i < 65536)
470 i <<= 16;
471 pattern->val.range.min = i;
472 i = 0;
473 continue;
474 }
475 j -= '0';
476 if (j > 9)
477 // also catches the terminating zero
478 break;
479 i = (i & 0xFFFF0000) + (i & 0xFFFF) * 10;
480 i += j;
481 }
482
483 /* if we only got a major version, let's shift it now */
484 if (i < 65536)
485 i <<= 16;
486
487 if (last && *opaque >= 1 && *opaque <= 4)
488 /* having a range with a min or a max is absurd */
489 return 0;
490
491 if (!last)
492 pattern->val.range.min = i;
493 pattern->val.range.max = i;
494
495 switch (*opaque) {
496 case 0: /* eq */
497 pattern->val.range.min_set = 1;
498 pattern->val.range.max_set = 1;
499 break;
500 case 1: /* gt */
501 pattern->val.range.min++; /* gt = ge + 1 */
502 case 2: /* ge */
503 pattern->val.range.min_set = 1;
504 pattern->val.range.max_set = 0;
505 break;
506 case 3: /* lt */
507 pattern->val.range.max--; /* lt = le - 1 */
508 case 4: /* le */
509 pattern->val.range.min_set = 0;
510 pattern->val.range.max_set = 1;
511 break;
512 }
513 return skip + 1;
514}
515
Willy Tarreaua67fad92007-05-08 19:50:09 +0200516/* Parse an IP address and an optional mask in the form addr[/mask].
517 * The addr may either be an IPv4 address or a hostname. The mask
518 * may either be a dotted mask or a number of bits. Returns 1 if OK,
519 * otherwise 0.
520 */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200521int acl_parse_ip(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreaua67fad92007-05-08 19:50:09 +0200522{
Willy Tarreauae8b7962007-06-09 23:10:04 +0200523 if (str2net(*text, &pattern->val.ipv4.addr, &pattern->val.ipv4.mask))
524 return 1;
525 else
526 return 0;
Willy Tarreaua67fad92007-05-08 19:50:09 +0200527}
528
Willy Tarreaua84d3742007-05-07 00:36:48 +0200529/*
530 * Registers the ACL keyword list <kwl> as a list of valid keywords for next
531 * parsing sessions.
532 */
533void acl_register_keywords(struct acl_kw_list *kwl)
534{
535 LIST_ADDQ(&acl_keywords.list, &kwl->list);
536}
537
538/*
539 * Unregisters the ACL keyword list <kwl> from the list of valid keywords.
540 */
541void acl_unregister_keywords(struct acl_kw_list *kwl)
542{
543 LIST_DEL(&kwl->list);
544 LIST_INIT(&kwl->list);
545}
546
547/* Return a pointer to the ACL <name> within the list starting at <head>, or
548 * NULL if not found.
549 */
550struct acl *find_acl_by_name(const char *name, struct list *head)
551{
552 struct acl *acl;
553 list_for_each_entry(acl, head, list) {
554 if (strcmp(acl->name, name) == 0)
555 return acl;
556 }
557 return NULL;
558}
559
560/* Return a pointer to the ACL keyword <kw>, or NULL if not found. Note that if
561 * <kw> contains an opening parenthesis, only the left part of it is checked.
562 */
563struct acl_keyword *find_acl_kw(const char *kw)
564{
565 int index;
566 const char *kwend;
567 struct acl_kw_list *kwl;
568
569 kwend = strchr(kw, '(');
570 if (!kwend)
571 kwend = kw + strlen(kw);
572
573 list_for_each_entry(kwl, &acl_keywords.list, list) {
574 for (index = 0; kwl->kw[index].kw != NULL; index++) {
575 if ((strncmp(kwl->kw[index].kw, kw, kwend - kw) == 0) &&
576 kwl->kw[index].kw[kwend-kw] == 0)
577 return &kwl->kw[index];
578 }
579 }
580 return NULL;
581}
582
583static void free_pattern(struct acl_pattern *pat)
584{
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +0200585
586 if (pat->ptr.ptr) {
587 if (pat->freeptrbuf)
588 pat->freeptrbuf(pat->ptr.ptr);
589
Willy Tarreaua84d3742007-05-07 00:36:48 +0200590 free(pat->ptr.ptr);
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +0200591 }
592
Willy Tarreaua84d3742007-05-07 00:36:48 +0200593 free(pat);
594}
595
596static void free_pattern_list(struct list *head)
597{
598 struct acl_pattern *pat, *tmp;
599 list_for_each_entry_safe(pat, tmp, head, list)
600 free_pattern(pat);
601}
602
603static struct acl_expr *prune_acl_expr(struct acl_expr *expr)
604{
605 free_pattern_list(&expr->patterns);
606 LIST_INIT(&expr->patterns);
607 if (expr->arg.str)
608 free(expr->arg.str);
609 expr->kw->use_cnt--;
610 return expr;
611}
612
613/* Parse an ACL expression starting at <args>[0], and return it.
614 * Right now, the only accepted syntax is :
615 * <subject> [<value>...]
616 */
617struct acl_expr *parse_acl_expr(const char **args)
618{
619 __label__ out_return, out_free_expr, out_free_pattern;
620 struct acl_expr *expr;
621 struct acl_keyword *aclkw;
622 struct acl_pattern *pattern;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200623 int opaque, patflags;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200624 const char *arg;
625
626 aclkw = find_acl_kw(args[0]);
627 if (!aclkw || !aclkw->parse)
628 goto out_return;
629
630 expr = (struct acl_expr *)calloc(1, sizeof(*expr));
631 if (!expr)
632 goto out_return;
633
634 expr->kw = aclkw;
635 aclkw->use_cnt++;
636 LIST_INIT(&expr->patterns);
637 expr->arg.str = NULL;
Willy Tarreaubb768912007-06-10 11:17:01 +0200638 expr->arg_len = 0;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200639
640 arg = strchr(args[0], '(');
641 if (arg != NULL) {
642 char *end, *arg2;
643 /* there is an argument in the form "subject(arg)" */
644 arg++;
645 end = strchr(arg, ')');
646 if (!end)
647 goto out_free_expr;
648 arg2 = (char *)calloc(1, end - arg + 1);
649 if (!arg2)
650 goto out_free_expr;
651 memcpy(arg2, arg, end - arg);
652 arg2[end-arg] = '\0';
Willy Tarreaubb768912007-06-10 11:17:01 +0200653 expr->arg_len = end - arg;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200654 expr->arg.str = arg2;
655 }
656
Willy Tarreaua84d3742007-05-07 00:36:48 +0200657 args++;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200658
659 /* check for options before patterns. Supported options are :
660 * -i : ignore case for all patterns by default
661 * -f : read patterns from those files
662 * -- : everything after this is not an option
663 */
664 patflags = 0;
665 while (**args == '-') {
666 if ((*args)[1] == 'i')
667 patflags |= ACL_PAT_F_IGNORE_CASE;
668 else if ((*args)[1] == 'f')
669 patflags |= ACL_PAT_F_FROM_FILE;
670 else if ((*args)[1] == '-') {
671 args++;
672 break;
673 }
674 else
675 break;
676 args++;
677 }
678
679 /* now parse all patterns */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200680 opaque = 0;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200681 while (**args) {
Willy Tarreauae8b7962007-06-09 23:10:04 +0200682 int ret;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200683 pattern = (struct acl_pattern *)calloc(1, sizeof(*pattern));
684 if (!pattern)
685 goto out_free_expr;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200686 pattern->flags = patflags;
687
Willy Tarreauae8b7962007-06-09 23:10:04 +0200688 ret = aclkw->parse(args, pattern, &opaque);
689 if (!ret)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200690 goto out_free_pattern;
691 LIST_ADDQ(&expr->patterns, &pattern->list);
Willy Tarreauae8b7962007-06-09 23:10:04 +0200692 args += ret;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200693 }
694
695 return expr;
696
697 out_free_pattern:
698 free_pattern(pattern);
699 out_free_expr:
700 prune_acl_expr(expr);
701 free(expr);
702 out_return:
703 return NULL;
704}
705
Krzysztof Piotr Oledzkia643baf2008-05-29 23:53:44 +0200706/* Purge everything in the acl <acl>, then return <acl>. */
707struct acl *prune_acl(struct acl *acl) {
708
709 struct acl_expr *expr, *exprb;
710
711 free(acl->name);
712
713 list_for_each_entry_safe(expr, exprb, &acl->expr, list) {
714 LIST_DEL(&expr->list);
715 prune_acl_expr(expr);
716 free(expr);
717 }
718
719 return acl;
720}
721
Willy Tarreaua84d3742007-05-07 00:36:48 +0200722/* Parse an ACL with the name starting at <args>[0], and with a list of already
723 * known ACLs in <acl>. If the ACL was not in the list, it will be added.
724 * A pointer to that ACL is returned.
725 *
726 * args syntax: <aclname> <acl_expr>
727 */
728struct acl *parse_acl(const char **args, struct list *known_acl)
729{
730 __label__ out_return, out_free_acl_expr, out_free_name;
731 struct acl *cur_acl;
732 struct acl_expr *acl_expr;
733 char *name;
734
Willy Tarreau2e74c3f2007-12-02 18:45:09 +0100735 if (invalid_char(*args))
736 goto out_return;
737
Willy Tarreaua84d3742007-05-07 00:36:48 +0200738 acl_expr = parse_acl_expr(args + 1);
739 if (!acl_expr)
740 goto out_return;
741
742 cur_acl = find_acl_by_name(args[0], known_acl);
743 if (!cur_acl) {
744 name = strdup(args[0]);
745 if (!name)
746 goto out_free_acl_expr;
747 cur_acl = (struct acl *)calloc(1, sizeof(*cur_acl));
748 if (cur_acl == NULL)
749 goto out_free_name;
750
751 LIST_INIT(&cur_acl->expr);
752 LIST_ADDQ(known_acl, &cur_acl->list);
753 cur_acl->name = name;
754 }
755
756 LIST_ADDQ(&cur_acl->expr, &acl_expr->list);
757 return cur_acl;
758
759 out_free_name:
760 free(name);
761 out_free_acl_expr:
762 prune_acl_expr(acl_expr);
763 free(acl_expr);
764 out_return:
765 return NULL;
766}
767
Willy Tarreau16fbe822007-06-17 11:54:31 +0200768/* Some useful ACLs provided by default. Only those used are allocated. */
769
770const struct {
771 const char *name;
772 const char *expr[4]; /* put enough for longest expression */
773} default_acl_list[] = {
Willy Tarreau58393e12008-07-20 10:39:22 +0200774 { .name = "TRUE", .expr = {"always_true",""}},
775 { .name = "FALSE", .expr = {"always_false",""}},
Willy Tarreau16fbe822007-06-17 11:54:31 +0200776 { .name = "LOCALHOST", .expr = {"src","127.0.0.1/8",""}},
777 { .name = "HTTP_1.0", .expr = {"req_ver","1.0",""}},
778 { .name = "HTTP_1.1", .expr = {"req_ver","1.1",""}},
779 { .name = "METH_CONNECT", .expr = {"method","CONNECT",""}},
780 { .name = "METH_GET", .expr = {"method","GET","HEAD",""}},
781 { .name = "METH_HEAD", .expr = {"method","HEAD",""}},
782 { .name = "METH_OPTIONS", .expr = {"method","OPTIONS",""}},
783 { .name = "METH_POST", .expr = {"method","POST",""}},
784 { .name = "METH_TRACE", .expr = {"method","TRACE",""}},
785 { .name = "HTTP_URL_ABS", .expr = {"url_reg","^[^/:]*://",""}},
786 { .name = "HTTP_URL_SLASH", .expr = {"url_beg","/",""}},
787 { .name = "HTTP_URL_STAR", .expr = {"url","*",""}},
788 { .name = "HTTP_CONTENT", .expr = {"hdr_val(content-length)","gt","0",""}},
Willy Tarreauc6317702008-07-20 09:29:50 +0200789 { .name = "REQ_CONTENT", .expr = {"req_len","gt","0",""}},
Willy Tarreaub6fb4202008-07-20 11:18:28 +0200790 { .name = "WAIT_END", .expr = {"wait_end",""}},
Willy Tarreau16fbe822007-06-17 11:54:31 +0200791 { .name = NULL, .expr = {""}}
792};
793
794/* Find a default ACL from the default_acl list, compile it and return it.
795 * If the ACL is not found, NULL is returned. In theory, it cannot fail,
796 * except when default ACLs are broken, in which case it will return NULL.
797 * If <known_acl> is not NULL, the ACL will be queued at its tail.
798 */
799struct acl *find_acl_default(const char *acl_name, struct list *known_acl)
800{
801 __label__ out_return, out_free_acl_expr, out_free_name;
802 struct acl *cur_acl;
803 struct acl_expr *acl_expr;
804 char *name;
805 int index;
806
807 for (index = 0; default_acl_list[index].name != NULL; index++) {
808 if (strcmp(acl_name, default_acl_list[index].name) == 0)
809 break;
810 }
811
812 if (default_acl_list[index].name == NULL)
813 return NULL;
814
815 acl_expr = parse_acl_expr((const char **)default_acl_list[index].expr);
816 if (!acl_expr)
817 goto out_return;
818
819 name = strdup(acl_name);
820 if (!name)
821 goto out_free_acl_expr;
822 cur_acl = (struct acl *)calloc(1, sizeof(*cur_acl));
823 if (cur_acl == NULL)
824 goto out_free_name;
825
826 cur_acl->name = name;
827 LIST_INIT(&cur_acl->expr);
828 LIST_ADDQ(&cur_acl->expr, &acl_expr->list);
829 if (known_acl)
830 LIST_ADDQ(known_acl, &cur_acl->list);
831
832 return cur_acl;
833
834 out_free_name:
835 free(name);
836 out_free_acl_expr:
837 prune_acl_expr(acl_expr);
838 free(acl_expr);
839 out_return:
840 return NULL;
841}
Willy Tarreaua84d3742007-05-07 00:36:48 +0200842
843/* Purge everything in the acl_cond <cond>, then return <cond>. */
844struct acl_cond *prune_acl_cond(struct acl_cond *cond)
845{
846 struct acl_term_suite *suite, *tmp_suite;
847 struct acl_term *term, *tmp_term;
848
849 /* iterate through all term suites and free all terms and all suites */
850 list_for_each_entry_safe(suite, tmp_suite, &cond->suites, list) {
851 list_for_each_entry_safe(term, tmp_term, &suite->terms, list)
852 free(term);
853 free(suite);
854 }
855 return cond;
856}
857
858/* Parse an ACL condition starting at <args>[0], relying on a list of already
859 * known ACLs passed in <known_acl>. The new condition is returned (or NULL in
860 * case of low memory). Supports multiple conditions separated by "or".
861 */
862struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int pol)
863{
864 __label__ out_return, out_free_suite, out_free_term;
Willy Tarreau74b98a82007-06-16 19:35:18 +0200865 int arg, neg;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200866 const char *word;
867 struct acl *cur_acl;
868 struct acl_term *cur_term;
869 struct acl_term_suite *cur_suite;
870 struct acl_cond *cond;
871
872 cond = (struct acl_cond *)calloc(1, sizeof(*cond));
873 if (cond == NULL)
874 goto out_return;
875
876 LIST_INIT(&cond->list);
877 LIST_INIT(&cond->suites);
878 cond->pol = pol;
879
880 cur_suite = NULL;
Willy Tarreau74b98a82007-06-16 19:35:18 +0200881 neg = 0;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200882 for (arg = 0; *args[arg]; arg++) {
883 word = args[arg];
884
885 /* remove as many exclamation marks as we can */
886 while (*word == '!') {
887 neg = !neg;
888 word++;
889 }
890
891 /* an empty word is allowed because we cannot force the user to
892 * always think about not leaving exclamation marks alone.
893 */
894 if (!*word)
895 continue;
896
Willy Tarreau16fbe822007-06-17 11:54:31 +0200897 if (strcasecmp(word, "or") == 0 || strcmp(word, "||") == 0) {
Willy Tarreaua84d3742007-05-07 00:36:48 +0200898 /* new term suite */
899 cur_suite = NULL;
900 neg = 0;
901 continue;
902 }
903
Willy Tarreau16fbe822007-06-17 11:54:31 +0200904 /* search for <word> in the known ACL names. If we do not find
905 * it, let's look for it in the default ACLs, and if found, add
906 * it to the list of ACLs of this proxy. This makes it possible
907 * to override them.
908 */
Willy Tarreaua84d3742007-05-07 00:36:48 +0200909 cur_acl = find_acl_by_name(word, known_acl);
Willy Tarreau16fbe822007-06-17 11:54:31 +0200910 if (cur_acl == NULL) {
911 cur_acl = find_acl_default(word, known_acl);
912 if (cur_acl == NULL)
913 goto out_free_suite;
914 }
Willy Tarreaua84d3742007-05-07 00:36:48 +0200915
916 cur_term = (struct acl_term *)calloc(1, sizeof(*cur_term));
917 if (cur_term == NULL)
918 goto out_free_suite;
919
920 cur_term->acl = cur_acl;
921 cur_term->neg = neg;
922
923 if (!cur_suite) {
924 cur_suite = (struct acl_term_suite *)calloc(1, sizeof(*cur_suite));
925 if (cur_term == NULL)
926 goto out_free_term;
927 LIST_INIT(&cur_suite->terms);
928 LIST_ADDQ(&cond->suites, &cur_suite->list);
929 }
930 LIST_ADDQ(&cur_suite->terms, &cur_term->list);
Willy Tarreau74b98a82007-06-16 19:35:18 +0200931 neg = 0;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200932 }
933
934 return cond;
935
936 out_free_term:
937 free(cur_term);
938 out_free_suite:
939 prune_acl_cond(cond);
940 free(cond);
941 out_return:
942 return NULL;
943}
944
Willy Tarreau11382812008-07-09 16:18:21 +0200945/* Execute condition <cond> and return either ACL_PAT_FAIL, ACL_PAT_MISS or
Willy Tarreaub6866442008-07-14 23:54:42 +0200946 * ACL_PAT_PASS depending on the test results. ACL_PAT_MISS may only be
947 * returned if <dir> contains ACL_PARTIAL, indicating that incomplete data
948 * is being examined.
949 * This function only computes the condition, it does not apply the polarity
950 * required by IF/UNLESS, it's up to the caller to do this using something like
951 * this :
Willy Tarreau11382812008-07-09 16:18:21 +0200952 *
953 * res = acl_pass(res);
Willy Tarreaub6866442008-07-14 23:54:42 +0200954 * if (res == ACL_PAT_MISS)
955 * return 0;
Willy Tarreau11382812008-07-09 16:18:21 +0200956 * if (cond->pol == ACL_COND_UNLESS)
957 * res = !res;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200958 */
Willy Tarreaud41f8d82007-06-10 10:06:18 +0200959int acl_exec_cond(struct acl_cond *cond, struct proxy *px, struct session *l4, void *l7, int dir)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200960{
961 __label__ fetch_next;
962 struct acl_term_suite *suite;
963 struct acl_term *term;
964 struct acl_expr *expr;
965 struct acl *acl;
966 struct acl_pattern *pattern;
967 struct acl_test test;
Willy Tarreau11382812008-07-09 16:18:21 +0200968 int acl_res, suite_res, cond_res;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200969
Willy Tarreau11382812008-07-09 16:18:21 +0200970 /* We're doing a logical OR between conditions so we initialize to FAIL.
971 * The MISS status is propagated down from the suites.
972 */
Willy Tarreaua84d3742007-05-07 00:36:48 +0200973 cond_res = ACL_PAT_FAIL;
974 list_for_each_entry(suite, &cond->suites, list) {
Willy Tarreau11382812008-07-09 16:18:21 +0200975 /* Evaluate condition suite <suite>. We stop at the first term
976 * which returns ACL_PAT_FAIL. The MISS status is still propagated
977 * in case of uncertainty in the result.
Willy Tarreaua84d3742007-05-07 00:36:48 +0200978 */
979
980 /* we're doing a logical AND between terms, so we must set the
981 * initial value to PASS.
982 */
983 suite_res = ACL_PAT_PASS;
984 list_for_each_entry(term, &suite->terms, list) {
985 acl = term->acl;
986
987 /* FIXME: use cache !
988 * check acl->cache_idx for this.
989 */
990
991 /* ACL result not cached. Let's scan all the expressions
992 * and use the first one to match.
993 */
994 acl_res = ACL_PAT_FAIL;
995 list_for_each_entry(expr, &acl->expr, list) {
Willy Tarreaud41f8d82007-06-10 10:06:18 +0200996 /* we need to reset context and flags */
997 memset(&test, 0, sizeof(test));
Willy Tarreaua84d3742007-05-07 00:36:48 +0200998 fetch_next:
Willy Tarreaub6866442008-07-14 23:54:42 +0200999 if (!expr->kw->fetch(px, l4, l7, dir, expr, &test)) {
1000 /* maybe we could not fetch because of missing data */
1001 if (test.flags & ACL_TEST_F_MAY_CHANGE && dir & ACL_PARTIAL)
1002 acl_res |= ACL_PAT_MISS;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001003 continue;
Willy Tarreaub6866442008-07-14 23:54:42 +02001004 }
Willy Tarreaua84d3742007-05-07 00:36:48 +02001005
Willy Tarreaua79534f2008-07-20 10:13:37 +02001006 if (test.flags & ACL_TEST_F_RES_SET) {
1007 if (test.flags & ACL_TEST_F_RES_PASS)
1008 acl_res |= ACL_PAT_PASS;
1009 else
1010 acl_res |= ACL_PAT_FAIL;
1011 }
1012 else {
1013 /* call the match() function for all tests on this value */
1014 list_for_each_entry(pattern, &expr->patterns, list) {
1015 acl_res |= expr->kw->match(&test, pattern);
1016 if (acl_res == ACL_PAT_PASS)
1017 break;
1018 }
Willy Tarreaua84d3742007-05-07 00:36:48 +02001019 }
1020 /*
Willy Tarreau11382812008-07-09 16:18:21 +02001021 * OK now acl_res holds the result of this expression
1022 * as one of ACL_PAT_FAIL, ACL_PAT_MISS or ACL_PAT_PASS.
Willy Tarreaua84d3742007-05-07 00:36:48 +02001023 *
Willy Tarreau11382812008-07-09 16:18:21 +02001024 * Then if (!MISS) we can cache the result, and put
Willy Tarreaua84d3742007-05-07 00:36:48 +02001025 * (test.flags & ACL_TEST_F_VOLATILE) in the cache flags.
1026 *
1027 * FIXME: implement cache.
1028 *
1029 */
1030
1031 /* now we may have some cleanup to do */
1032 if (test.flags & ACL_TEST_F_MUST_FREE) {
1033 free(test.ptr);
1034 test.len = 0;
1035 }
1036
Willy Tarreau11382812008-07-09 16:18:21 +02001037 /* we're ORing these terms, so a single PASS is enough */
1038 if (acl_res == ACL_PAT_PASS)
Willy Tarreaua84d3742007-05-07 00:36:48 +02001039 break;
1040
Willy Tarreaua84d3742007-05-07 00:36:48 +02001041 if (test.flags & ACL_TEST_F_FETCH_MORE)
1042 goto fetch_next;
Willy Tarreaub6866442008-07-14 23:54:42 +02001043
1044 /* sometimes we know the fetched data is subject to change
1045 * later and give another chance for a new match (eg: request
1046 * size, time, ...)
1047 */
1048 if (test.flags & ACL_TEST_F_MAY_CHANGE && dir & ACL_PARTIAL)
1049 acl_res |= ACL_PAT_MISS;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001050 }
1051 /*
1052 * Here we have the result of an ACL (cached or not).
1053 * ACLs are combined, negated or not, to form conditions.
1054 */
1055
Willy Tarreaua84d3742007-05-07 00:36:48 +02001056 if (term->neg)
Willy Tarreau11382812008-07-09 16:18:21 +02001057 acl_res = acl_neg(acl_res);
Willy Tarreaua84d3742007-05-07 00:36:48 +02001058
1059 suite_res &= acl_res;
Willy Tarreau11382812008-07-09 16:18:21 +02001060
1061 /* we're ANDing these terms, so a single FAIL is enough */
1062 if (suite_res == ACL_PAT_FAIL)
Willy Tarreaua84d3742007-05-07 00:36:48 +02001063 break;
1064 }
1065 cond_res |= suite_res;
Willy Tarreau11382812008-07-09 16:18:21 +02001066
1067 /* we're ORing these terms, so a single PASS is enough */
1068 if (cond_res == ACL_PAT_PASS)
Willy Tarreaua84d3742007-05-07 00:36:48 +02001069 break;
1070 }
Willy Tarreau11382812008-07-09 16:18:21 +02001071 return cond_res;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001072}
1073
1074
1075/************************************************************************/
1076/* All supported keywords must be declared here. */
1077/************************************************************************/
1078
1079/* Note: must not be declared <const> as its list will be overwritten */
1080static struct acl_kw_list acl_kws = {{ },{
Willy Tarreau58393e12008-07-20 10:39:22 +02001081 { "always_true", acl_parse_nothing, acl_fetch_true, acl_match_nothing },
1082 { "always_false", acl_parse_nothing, acl_fetch_false, acl_match_nothing },
Willy Tarreaub6fb4202008-07-20 11:18:28 +02001083 { "wait_end", acl_parse_nothing, acl_fetch_wait_end, acl_match_nothing },
Willy Tarreaua84d3742007-05-07 00:36:48 +02001084#if 0
1085 { "time", acl_parse_time, acl_fetch_time, acl_match_time },
1086#endif
1087 { NULL, NULL, NULL, NULL }
1088}};
1089
1090
1091__attribute__((constructor))
1092static void __acl_init(void)
1093{
1094 acl_register_keywords(&acl_kws);
1095}
1096
1097
1098/*
1099 * Local variables:
1100 * c-indent-level: 8
1101 * c-basic-offset: 8
1102 * End:
1103 */