From: Willy Tarreau Date: Sun, 9 May 2010 21:45:24 +0000 (+0200) Subject: [MINOR] acl: support loading values from files X-Git-Tag: v1.4.5~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2b5285da333ec711789a0806bd840cc7bcba0fa5;p=thirdparty%2Fhaproxy.git [MINOR] acl: support loading values from files The "acl XXX -f " syntax was supported but nothing was read from the file. This is now possible. All lines are merged verbatim, even if they contain spaces (useful for user-agents). There are shortcomings though. The worst one is that error reporting is too approximative. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index 47e4ed4060..1ca54fe809 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -5886,9 +5886,27 @@ performance, they just consume a small amount of memory. The following ACL flags are currently supported : - -i : ignore case during matching. + -i : ignore case during matching of all subsequent patterns. + -f : load patterns from a file. -- : force end of flags. Useful when a string looks like one of the flags. +The "-f" flag is special as it loads all of the lines it finds in the file +specified in argument and loads all of them before continuing. It is even +possible to pass multiple "-f" arguments if the patterns are to be loaded from +multiple files. Also, note that the "-i" flag applies to subsequent entries and +not to entries loaded from files preceeding it. For instance : + + acl valid-ua hdr(user-agent) -f exact-ua.lst -i -f generic-ua.lst test + +In this example, each line of "exact-ua.lst" will be exactly matched against +the "user-agent" header of the request. Then each line of "generic-ua" will be +case-insensitively matched. Then the word "test" will be insensitively matched +too. + +Note that right now it is difficult for the ACL parsers to report errors, so if +a file is unreadable or unparsable, the most you'll get is a parse error in the +ACL. Thus, file-based ACLs should only be produced by reliable processes. + Supported types of values are : - integers or integer ranges diff --git a/src/acl.c b/src/acl.c index be752b069f..a4ea068f6c 100644 --- a/src/acl.c +++ b/src/acl.c @@ -19,6 +19,8 @@ #include #include +#include + #include #include #include @@ -658,6 +660,52 @@ static struct acl_expr *prune_acl_expr(struct acl_expr *expr) return expr; } +static int acl_read_patterns_from_file( struct acl_keyword *aclkw, + struct acl_expr *expr, + const char *filename, int patflags) +{ + FILE *file; + char *c; + const char *args[2]; + struct acl_pattern *pattern; + int opaque; + + file = fopen(filename, "r"); + if (!file) + return 0; + + /* now parse all patterns. The file may contain only one pattern per + * line. If the line contains spaces, they will be part of the pattern. + * The pattern stops at the first CR, LF or EOF encountered. + */ + opaque = 0; + args[0] = trash; + args[1] = ""; + while (fgets(trash, sizeof(trash), file) != NULL) { + + c = trash; + while (*c && *c != '\n' && *c != '\r') + c++; + *c = 0; + + pattern = (struct acl_pattern *)calloc(1, sizeof(*pattern)); + if (!pattern) + goto out_close; + pattern->flags = patflags; + + if (!aclkw->parse(args, pattern, &opaque)) + goto out_free_pattern; + LIST_ADDQ(&expr->patterns, &pattern->list); + } + return 1; + + out_free_pattern: + free_pattern(pattern); + out_close: + fclose(file); + return 0; +} + /* Parse an ACL expression starting at [0], and return it. * Right now, the only accepted syntax is : * [...] @@ -711,8 +759,11 @@ struct acl_expr *parse_acl_expr(const char **args) while (**args == '-') { if ((*args)[1] == 'i') patflags |= ACL_PAT_F_IGNORE_CASE; - else if ((*args)[1] == 'f') - patflags |= ACL_PAT_F_FROM_FILE; + else if ((*args)[1] == 'f') { + if (!acl_read_patterns_from_file(aclkw, expr, args[1], patflags | ACL_PAT_F_FROM_FILE)) + goto out_free_expr; + args++; + } else if ((*args)[1] == '-') { args++; break;