From 23009db46e81e5918bda788b31ab5e263d901182 Mon Sep 17 00:00:00 2001 From: Maxim Antonov Date: Tue, 13 Oct 2020 17:28:52 +0700 Subject: [PATCH] Add the new action suppress-tag{} Usage: in user.filters: --begin-- CLIENT-HEADER-TAGGER: maximum-url-length Tag for URLS longer than 600 characters. s@(^GET\s+\/.{600,}\s+HTTP\/\d\.\d\s*$)@MAXIMUM-URL-LENGTH@i --end-- in user.actions: --begin-- {+client-header-tagger{maximum-url-length}} / {+block{Maximum URL length of 600 bytes reached.}} TAG:^MAXIMUM-URL-LENGTH {+suppress-tag{MAXIMUM-URL-LENGTH}} .google.* --end-- will block all URLs with length > 600 bytes except for google. Currently the online action editor supports modification/removal of any number of existing tags and the creation of a single suppress tag per one submit. The submit scheme that is used is similar to the existing filter one but: 1. It uses 'string_filter[_r|_n|_o|_t][hex_index]' keys for existing string filter values (id/name(value)/old_name(old value)/filter type) and 'new_string_filter[_r|_n|_t][hex_index]' for new string filter values. 'String filter values' here are parameters of the suppress-tag action that are simple strings rather than parameters of, for example, the client-header-tagger action that must be described in filters file. 2. String filter values are accessed by the value rather by the index. Indexes must start from 0 and when there is no key with index+1 in parameters - we've done with existing or new string filters processing. Possible further improvements: 1. Extend suppress-tag action edit scheme to add-header action edit that is not supported now. 2. If needed, multiple suppress-tag addition can be added with some browser JS code. Sponsored by: Robert Klemme --- actionlist.h | 1 + actions.c | 2 + cgiedit.c | 231 ++++++++++++++++++- doc/source/user-manual.sgml | 57 +++++ parsers.c | 9 + project.h | 9 +- templates/edit-actions-for-url | 24 ++ templates/edit-actions-for-url-string-filter | 40 ++++ 8 files changed, 368 insertions(+), 5 deletions(-) create mode 100644 templates/edit-actions-for-url-string-filter diff --git a/actionlist.h b/actionlist.h index 5f94ea4f..6129bb00 100644 --- a/actionlist.h +++ b/actionlist.h @@ -129,6 +129,7 @@ DEFINE_ACTION_STRING ("set-image-blocker", ACTION_IMAGE_BLOCKER, DEFINE_CGI_PARAM_RADIO ("set-image-blocker", ACTION_IMAGE_BLOCKER, ACTION_STRING_IMAGE_BLOCKER, "pattern", 1) DEFINE_CGI_PARAM_RADIO ("set-image-blocker", ACTION_IMAGE_BLOCKER, ACTION_STRING_IMAGE_BLOCKER, "blank", 0) DEFINE_CGI_PARAM_CUSTOM ("set-image-blocker", ACTION_IMAGE_BLOCKER, ACTION_STRING_IMAGE_BLOCKER, CGI_PREFIX "send-banner?type=pattern") +DEFINE_ACTION_MULTI ("suppress-tag", ACTION_MULTI_SUPPRESS_TAG) #if DEFINE_ACTION_ALIAS diff --git a/actions.c b/actions.c index 775350af..7905231f 100644 --- a/actions.c +++ b/actions.c @@ -1115,6 +1115,8 @@ static const char *filter_type_to_string(enum filter_type filter_type) case FT_EXTERNAL_CONTENT_FILTER: return "external content filter"; #endif + case FT_SUPPRESS_TAG: + return "suppress tag filter"; case FT_INVALID_FILTER: return "invalid filter type"; } diff --git a/cgiedit.c b/cgiedit.c index 64c8dc11..af22d071 100644 --- a/cgiedit.c +++ b/cgiedit.c @@ -248,6 +248,12 @@ static const struct filter_type_info filter_type_info[] = "E", "EXTERNAL-CONTENT-FILTER" }, #endif + { + ACTION_MULTI_SUPPRESS_TAG, + "suppress-tag-params", "suppress-tag", + "suppress-tag-all", "suppress_tag_all", + "U", "SUPPRESS-TAG" + }, }; /* FIXME: Following non-static functions should be prototyped in .h or made static */ @@ -306,6 +312,10 @@ static jb_err actions_to_radio(struct map * exports, const struct action_spec *action); static jb_err actions_from_radio(const struct map * parameters, struct action_spec *action); +static jb_err action_render_string_filters_template(struct map * exports, + const struct action_spec *action, + const char* flter_template, + const struct filter_type_info *type); static jb_err map_copy_parameter_html(struct map *out, @@ -2685,6 +2695,7 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, const struct map *parameters) { struct map * exports; + char *filter_template; unsigned sectionid; struct editable_file * file; struct file_line * cur_line; @@ -2734,12 +2745,24 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, return JB_ERR_MEMORY; } + err = template_load(csp, &filter_template, "edit-actions-for-url-string-filter", 0); + if (err) + { + edit_free_file(file); + free_map(exports); + return cgi_error_no_template(csp, rsp, "edit-actions-for-url-string-filter"); + } + err = map(exports, "f", 1, stringify(file->identifier), 0); if (!err) err = map(exports, "v", 1, file->version_str, 1); if (!err) err = map(exports, "s", 1, url_encode(lookup(parameters, "s")), 0); if (!err) err = actions_to_radio(exports, cur_line->data.action); + if (!err) err = action_render_string_filters_template(exports, cur_line->data.action, filter_template, + &filter_type_info[FT_SUPPRESS_TAG]); + freez(filter_template); + /* * XXX: Some browsers (at least IE6 and IE7) have an artificial URL * length limitation and ignore clicks on the Submit buttons if @@ -2802,7 +2825,6 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, /* * List available filters and their settings. */ - char *filter_template; int filter_identifier = 0; char *prepared_templates[MAX_FILTER_TYPES]; @@ -2893,7 +2915,7 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, if (filter_line == NULL) err = JB_ERR_MEMORY; } if (!err) err = template_fill(&filter_line, line_exports); - string_join(&prepared_templates[type], filter_line); + if (!err) err = string_join(&prepared_templates[type], filter_line); free_map(line_exports); } @@ -3195,6 +3217,133 @@ jb_err cgi_edit_actions_submit(struct client_state *csp, } } + /* process existing suppress tag */ + for (filter_identifier = 0; !err; filter_identifier++) + { + char key_value[30]; + char key_name[30]; + char old_name[30]; + char key_type[30]; + const char *name, *new_name; + char value; /* + * Filter state. Valid states are: 'Y' (active), + * 'N' (inactive) and 'X' (no change). + * XXX: bad name. + */ + char type; /* + * Abbreviated filter type. Valid types are: 'U' (suppress tag). + */ + int multi_action_index = 0; + + /* Generate the keys */ + snprintf(key_value, sizeof(key_value), "string_filter_r%x", filter_identifier); + snprintf(key_name, sizeof(key_name), "string_filter_n%x", filter_identifier); + snprintf(old_name, sizeof(old_name), "string_filter_o%x", filter_identifier); + snprintf(key_type, sizeof(key_type), "string_filter_t%x", filter_identifier); + + err = get_string_param(parameters, old_name, &name); + if (err) break; + + if (name == NULL) + { + /* The filter identifier isn't present: we're done! */ + break; + } + + err = get_string_param(parameters, key_name, &new_name); + if (err) break; + if (new_name == NULL) new_name = name; + + type = get_char_param(parameters, key_type); + switch (type) + { + case 'U': + multi_action_index = ACTION_MULTI_SUPPRESS_TAG; + break; + default: + log_error(LOG_LEVEL_ERROR, + "Unknown filter type: %c for filter %s. Filter ignored.", type, name); + continue; + } + assert(multi_action_index); + + value = get_char_param(parameters, key_value); + if (value == 'X' || value == 'Y' || value == 'N') + { + list_remove_item(cur_line->data.action->multi_add[multi_action_index], name); + list_remove_item(cur_line->data.action->multi_remove[multi_action_index], name); + } + + if (value == 'Y') + { + err = enlist(cur_line->data.action->multi_add[multi_action_index], new_name); + } + else if (value == 'N') + { + err = enlist(cur_line->data.action->multi_remove[multi_action_index], new_name); + } + } + + /* process new string filters */ + for (filter_identifier = 0; !err; filter_identifier++) + { + char key_value[30]; + char key_name[30]; + char key_type[30]; + const char *name; + char value; /* + * Filter state. Valid states are: 'Y' (active), + * 'N' (inactive) and 'X' (no change). + * XXX: bad name. + */ + char type; /* + * Abbreviated filter type. Valid types are: 'U' (suppress tag). + */ + int multi_action_index = 0; + + /* Generate the keys */ + snprintf(key_value, sizeof(key_value), "new_string_filter_r%x", filter_identifier); + snprintf(key_name, sizeof(key_name), "new_string_filter_n%x", filter_identifier); + snprintf(key_type, sizeof(key_type), "new_string_filter_t%x", filter_identifier); + + err = get_string_param(parameters, key_name, &name); + if (err) break; + + if (name == NULL) + { + /* The filter identifier isn't present: we've done! */ + break; + } + + type = get_char_param(parameters, key_type); + switch (type) + { + case 'U': + multi_action_index = ACTION_MULTI_SUPPRESS_TAG; + break; + default: + log_error(LOG_LEVEL_ERROR, + "Unknown filter type: %c for filter %s. Filter ignored.", type, name); + continue; + } + assert(multi_action_index); + + value = get_char_param(parameters, key_value); + if (value == 'Y') + { + list_remove_item(cur_line->data.action->multi_add[multi_action_index], name); + if (!err) err = enlist(cur_line->data.action->multi_add[multi_action_index], name); + list_remove_item(cur_line->data.action->multi_remove[multi_action_index], name); + } + else if (value == 'N') + { + list_remove_item(cur_line->data.action->multi_add[multi_action_index], name); + list_remove_item(cur_line->data.action->multi_remove[multi_action_index], name); + if (!err) err = enlist(cur_line->data.action->multi_remove[multi_action_index], name); + } + /* nothing to do if the value is 'X' */ + } + if (err) { /* Out of memory */ @@ -4248,6 +4397,84 @@ static jb_err actions_to_radio(struct map * exports, return JB_ERR_OK; } +/********************************************************************* + * + * Function : action_render_string_filters_template + * + * Description : Converts a actionsfile entry into HTML template for actions with string + * filters (currently SUPPRESS-TAG actions only) + * + * Parameters : + * 1 : exports = List of substitutions to add to. + * 2 : action = Action to read + * 3 : filter_template = template to fill + * 4 : type = filter type info for rendered values/macro name + * + * Returns : JB_ERR_OK on success + * JB_ERR_MEMORY on out-of-memory + * + *********************************************************************/ +static jb_err action_render_string_filters_template(struct map * exports, + const struct action_spec *action, + const char* filter_template, + const struct filter_type_info *type) +{ + jb_err err = JB_ERR_OK; + int filter_identifier = 0; + char *prepared_template = strdup(""); + + struct action_multi { + char radio; + struct list_entry *list; + }; + + struct action_multi desc[] = { + { 'y', action->multi_add[type->multi_action_index][0].first }, + { 'n', action->multi_remove[type->multi_action_index][0].first } + }; + + for (int i=0; i < SZ(desc); ++i) + { + const char radio = desc[i].radio; + struct list_entry *entry = desc[i].list; + for (;(!err) && (entry != NULL); entry = entry->next) + { + char number[20]; + struct map *line_exports; + + /* Generate a unique serial number */ + snprintf(number, sizeof(number), "%x", filter_identifier++); + + line_exports = new_map(); + if (line_exports == NULL) + { + err = JB_ERR_MEMORY; + } + else + { + char *filter_line; + if (!err) err = map(line_exports, "index", 1, number, 1); + if (!err) err = map(line_exports, "name", 1, entry->str, 1); + if (!err) err = map_radio(line_exports, "this-filter", "ynx", radio); + if (!err) err = map(line_exports, "filter-type", 1, type->type, 1); + if (!err) err = map(line_exports, "abbr-filter-type", 1, type->abbr_type, 1); + if (!err) err = map(line_exports, "anchor", 1, type->anchor, 1); + if (!err) + { + filter_line = strdup(filter_template); + if (filter_line == NULL) err = JB_ERR_MEMORY; + } + if (!err) err = template_fill(&filter_line, line_exports); + if (!err) err = string_join(&prepared_template, filter_line); + + free_map(line_exports); + } + } + } + if (!err) map(exports, type->macro_name, 1, prepared_template, 1); + freez(prepared_template); + return err; +} /********************************************************************* * diff --git a/doc/source/user-manual.sgml b/doc/source/user-manual.sgml index 60c437fa..cb1243d8 100644 --- a/doc/source/user-manual.sgml +++ b/doc/source/user-manual.sgml @@ -5936,6 +5936,63 @@ TAG:^image/ + + +suppress-tag + + + + Typical use: + + + Suppress client or server tag. + + + + + + Effect: + + + Server or client tags to which this action applies are not added to the request, + thus making all actions that are specific to these request tags inactive. + + + + + + Type: + + + Multi-value. + + + + + Parameter: + + + The result tag of a server-header or client-header tagger, as defined in one of the + filter files. + + + + + + Example usage (section): + + +# Suppress tag produced by range-requests client-header tagger for requests coming from address 10.0.0.1 +{+suppress-tag{RANGE-REQUEST}} +TAG:^IP-ADDRESS: 10\.0\.0\.1$ + + + + + + + + session-cookies-only diff --git a/parsers.c b/parsers.c index eab5e76b..d2ef046a 100644 --- a/parsers.c +++ b/parsers.c @@ -1540,6 +1540,15 @@ static jb_err header_tagger(struct client_state *csp, char *header) continue; } + if (list_contains_item(csp->action->multi[ACTION_MULTI_SUPPRESS_TAG], tag)) + { + log_error(LOG_LEVEL_HEADER, + "Tagger \'%s\' didn't add tag \'%s\': suppressed", + b->name, tag); + freez(tag); + continue; + } + if (!list_contains_item(csp->tags, tag)) { if (JB_ERR_OK != enlist(csp->tags, tag)) diff --git a/project.h b/project.h index e07c7616..43792dde 100644 --- a/project.h +++ b/project.h @@ -649,8 +649,10 @@ struct iob #define ACTION_MULTI_SERVER_HEADER_TAGGER 5 /** Number of multi-string actions. */ #define ACTION_MULTI_EXTERNAL_FILTER 6 +/** Index into current_action_spec::multi[] for tags to suppress. */ +#define ACTION_MULTI_SUPPRESS_TAG 7 /** Number of multi-string actions. */ -#define ACTION_MULTI_COUNT 7 +#define ACTION_MULTI_COUNT 8 /** @@ -1303,13 +1305,14 @@ enum filter_type #ifdef FEATURE_EXTERNAL_FILTERS FT_EXTERNAL_CONTENT_FILTER = 5, #endif + FT_SUPPRESS_TAG = 6, FT_INVALID_FILTER = 42, }; #ifdef FEATURE_EXTERNAL_FILTERS -#define MAX_FILTER_TYPES 6 +#define MAX_FILTER_TYPES 7 #else -#define MAX_FILTER_TYPES 5 +#define MAX_FILTER_TYPES 6 #endif /** diff --git a/templates/edit-actions-for-url b/templates/edit-actions-for-url index e3a240cd..1b9ed4f9 100644 --- a/templates/edit-actions-for-url +++ b/templates/edit-actions-for-url @@ -1142,6 +1142,30 @@ function show_limit_connect_opts(tf) you can enable or disable the taggers individually below. @server-header-tagger-params@ +@suppress-tag-params@ + + + + + suppress-tag + Suppress tag. + + +   +   +   +   + Tag to suppress:
+ + + + + + + + + + + + @filter-type@ @name@ + + Suppress tag + + +   +   +   +   + Tag to suppress:
+ + + -- 2.39.2