diff --git a/GNUmakefile.in b/GNUmakefile.in index 214a8e1..f48fd18 100644 --- a/GNUmakefile.in +++ b/GNUmakefile.in @@ -265,6 +265,11 @@ REGEX_SRC = REGEX_OBJS = $(REGEX_SRC:.c=.@OBJEXT@) REGEX_HDRS = $(REGEX_SRC:.c=.h) +# Required tag +RTAG_SRC = @REQUIRED_TAG_ONLY@requiredtag.c +RTAG_OBJS = @REQUIRED_TAG_ONLY@$(RTAG_SRC:.c=.@OBJEXT@) +RTAG_HDRS = @REQUIRED_TAG_ONLY@requiredtag.h + # Dependencies introduced by #include "project.h". PROJECT_H_DEPS = project.h $(REGEX_HDRS) $(PCRS_HDRS) @@ -274,9 +279,9 @@ SOCKET_LIB = @SOCKET_LIB@ # PThreads library, if needed. PTHREAD_LIB = @PTHREAD_ONLY@@PTHREAD_LIB@ -SRCS = $(C_SRC) $(CLIENT_TAG_SRC) $(FUZZ_SRC) $(W32_SRC) $(PCRS_SRC) $(REGEX_SRC) $(SSL_SRC) $(MBEDTLS_SRC) $(OPENSSL_SRC) $(WOLFSSL_SRC) -OBJS = $(C_OBJS) $(CLIENT_TAG_OBJS) $(FUZZ_OBJS) $(W32_OBJS) $(PCRS_OBJS) $(REGEX_OBJS) $(SSL_OBJS) $(MBEDTLS_OBJS) $(OPENSSL_OBJS) $(WOLFSSL_OBJS) -HDRS = $(C_HDRS) $(W32_HDRS) $(PCRS_HDRS) $(REGEX_HDRS) $(SSL_HDRS) $(MBEDTLS_HDRS) $(OPENSSL_HDRS) $(WOLFSSL_HDRS) +SRCS = $(C_SRC) $(CLIENT_TAG_SRC) $(FUZZ_SRC) $(W32_SRC) $(PCRS_SRC) $(REGEX_SRC) $(SSL_SRC) $(MBEDTLS_SRC) $(OPENSSL_SRC) $(WOLFSSL_SRC) $(RTAG_SRC) +OBJS = $(C_OBJS) $(CLIENT_TAG_OBJS) $(FUZZ_OBJS) $(W32_OBJS) $(PCRS_OBJS) $(REGEX_OBJS) $(SSL_OBJS) $(MBEDTLS_OBJS) $(OPENSSL_OBJS) $(WOLFSSL_OBJS) $(RTAG_OBJS) +HDRS = $(C_HDRS) $(W32_HDRS) $(PCRS_HDRS) $(REGEX_HDRS) $(SSL_HDRS) $(MBEDTLS_HDRS) $(OPENSSL_HDRS) $(WOLFSSL_HDRS) $(RTAG_HDRS) LIBS = @LIBS@ $(W32_LIB) $(SOCKET_LIB) $(PTHREAD_LIB) @@ -549,8 +554,8 @@ man: dok-release mkdir -p doc/source/temp && cd doc/source/temp && $(RM) * ;\ $(NSGMLS) ../privoxy-man-page.sgml | sgmlspl ../../../utils/docbook2man/docbook2man-spec.pl &&\ perl -pi.bak -e 's/ //; s/\[ /\[/g' $(PRIVOXY_MAN_PAGE) ;\ - perl -pi.bak -e "s/\[ /\[/g;s/・\\\\['a]/g;s/・\\\\['e]/g" $(PRIVOXY_MAN_PAGE); \ - perl -pi.bak -e "s/・\\\\[:o]/g" $(PRIVOXY_MAN_PAGE); \ + perl -pi.bak -e "s/\[ /\[/g;s/・ス/\\\\['a]/g;s/・ス/\\\\['e]/g" $(PRIVOXY_MAN_PAGE); \ + perl -pi.bak -e "s/・ス/\\\\[:o]/g" $(PRIVOXY_MAN_PAGE); \ perl -pi.bak -e 's/([ {])-([a-z])/$$1\\-$$2/g' $(PRIVOXY_MAN_PAGE); \ perl -pi.bak -e 's/ --([a-z])/ \\-\\-$$1/g' $(PRIVOXY_MAN_PAGE); \ perl -pi.bak -e 's/\\fB--/\\fB\\-\\-/g' $(PRIVOXY_MAN_PAGE); \ @@ -775,6 +780,9 @@ ssl.@OBJEXT@: ssl.c ssl.h ssl_common.h config.h $(PROJECT_H_DEPS) encode.h errlo openssl.@OBJEXT@: openssl.c ssl.h ssl_common.h config.h $(PROJECT_H_DEPS) encode.h errlog.h jcc.h miscutil.h ssl_common.@OBJEXT@: ssl_common.c ssl.h ssl_common.h config.h $(PROJECT_H_DEPS) errlog.h miscutil.h +# required tag +required.tag.@OBJEXT@: requiredtag.c requiredtag.h config.h $(PROJECT_H_DEPS) errlog.h miscutil.h + # PCRS pcrs.@OBJEXT@: pcrs.c pcrs.h config.h diff --git a/acconfig.h b/acconfig.h index 9fbe5a7..877f6d9 100644 --- a/acconfig.h +++ b/acconfig.h @@ -54,11 +54,21 @@ */ #undef VERSION_POINT +/* + * Patchlevel + */ +#undef PATCHLEVEL + /* * Version number, as a string */ #undef VERSION +/* + * Version number of referenced document, as a string + */ +#undef DOC_VERSION + /* * Status of the code: "alpha", "beta" or "stable". */ @@ -180,6 +190,26 @@ */ #undef FEATURE_TRUST +/* + * Enables add-referer action and extended parameters for hide-referer action. + */ +#undef FEATURE_ADD_REFERER + +/* + * Enables forward class selection. + */ +#undef FEATURE_FORWARD_CLASS + +/* + * Enables manual tagger. + */ +#undef FEATURE_MANUAL_TAGGER + +/* + * Enables required tag. + */ +#undef FEATURE_REQUIRED_TAG + /* * Defined on Solaris only. Makes the system libraries thread safe. */ diff --git a/actionlist.h b/actionlist.h index d95b822..c30c738 100644 --- a/actionlist.h +++ b/actionlist.h @@ -51,6 +51,13 @@ #endif /* ndef DEFINE_CGI_PARAM_RADIO */ DEFINE_ACTION_MULTI ("add-header", ACTION_MULTI_ADD_HEADER) +DEFINE_ACTION_STRING ("add-referrer", ACTION_ADD_REFERER, ACTION_STRING_ADD_REFERER) +DEFINE_CGI_PARAM_RADIO ("add-referrer", ACTION_ADD_REFERER, ACTION_STRING_ADD_REFERER, "self", 4) +DEFINE_CGI_PARAM_RADIO ("add-referrer", ACTION_ADD_REFERER, ACTION_STRING_ADD_REFERER, "index", 3) +DEFINE_CGI_PARAM_RADIO ("add-referrer", ACTION_ADD_REFERER, ACTION_STRING_ADD_REFERER, "directory", 2) +DEFINE_CGI_PARAM_RADIO ("add-referrer", ACTION_ADD_REFERER, ACTION_STRING_ADD_REFERER, "forge", 1) +DEFINE_CGI_PARAM_RADIO ("add-referrer", ACTION_ADD_REFERER, ACTION_STRING_ADD_REFERER, "block", 0) +DEFINE_CGI_PARAM_CUSTOM ("add-referrer", ACTION_ADD_REFERER, ACTION_STRING_ADD_REFERER, "http://www.privoxy.org/") DEFINE_ACTION_STRING ("block", ACTION_BLOCK, ACTION_STRING_BLOCK) DEFINE_CGI_PARAM_NO_RADIO("block", ACTION_BLOCK, ACTION_STRING_BLOCK, "No reason specified.") DEFINE_ACTION_STRING ("change-x-forwarded-for", ACTION_CHANGE_X_FORWARDED_FOR, ACTION_STRING_CHANGE_X_FORWARDED_FOR) @@ -102,6 +109,9 @@ DEFINE_ACTION_STRING ("hide-if-modified-since", ACTION_HIDE_IF_MODIFIED_ DEFINE_CGI_PARAM_RADIO ("hide-if-modified-since", ACTION_HIDE_IF_MODIFIED_SINCE, ACTION_STRING_IF_MODIFIED_SINCE, "block", 0) DEFINE_CGI_PARAM_CUSTOM ("hide-if-modified-since", ACTION_HIDE_IF_MODIFIED_SINCE, ACTION_STRING_IF_MODIFIED_SINCE, "-1") DEFINE_ACTION_STRING ("hide-referrer", ACTION_HIDE_REFERER, ACTION_STRING_REFERER) +DEFINE_CGI_PARAM_RADIO ("hide-referrer", ACTION_HIDE_REFERER, ACTION_STRING_REFERER, "self", 6) +DEFINE_CGI_PARAM_RADIO ("hide-referrer", ACTION_HIDE_REFERER, ACTION_STRING_REFERER, "index", 5) +DEFINE_CGI_PARAM_RADIO ("hide-referrer", ACTION_HIDE_REFERER, ACTION_STRING_REFERER, "directory", 4) DEFINE_CGI_PARAM_RADIO ("hide-referrer", ACTION_HIDE_REFERER, ACTION_STRING_REFERER, "conditional-forge", 3) DEFINE_CGI_PARAM_RADIO ("hide-referrer", ACTION_HIDE_REFERER, ACTION_STRING_REFERER, "conditional-block", 2) DEFINE_CGI_PARAM_RADIO ("hide-referrer", ACTION_HIDE_REFERER, ACTION_STRING_REFERER, "forge", 1) @@ -138,6 +148,7 @@ DEFINE_ACTION_MULTI ("suppress-tag", ACTION_MULTI_SUPPRESS_TA /* * Alternative spellings */ +DEFINE_ACTION_STRING ("add-referer", ACTION_ADD_REFERER, ACTION_STRING_ADD_REFERER) DEFINE_ACTION_STRING ("hide-referer", ACTION_HIDE_REFERER, ACTION_STRING_REFERER) DEFINE_ACTION_BOOL ("prevent-keeping-cookies", ACTION_SESSION_COOKIES_ONLY) diff --git a/actions.c b/actions.c index 321e827..6454e60 100644 --- a/actions.c +++ b/actions.c @@ -55,6 +55,9 @@ #include "cgi.h" #include "ssplit.h" #include "filters.h" +#ifdef FEATURE_REQUIRED_TAG +#include "requiredtag.h" +#endif /* def FEATURE_REQUIRED_TAG */ /* * We need the main list of options. @@ -783,6 +786,36 @@ jb_err merge_current_action (struct current_action_spec *dest, return err; } +#ifdef FEATURE_MANUAL_TAGGER +/********************************************************************* + * + * Function : update_action_bits_for_all_tags + * + * Description : Updates the action bits based on all matching tags. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : 0 if no tag matched, or + * 1 otherwise + * + *********************************************************************/ +int update_action_bits_for_all_tags(struct client_state *csp) +{ + struct list_entry *tag; + int updated = 0; + + for (tag = csp->tags->first; tag != NULL; tag = tag->next) + { + if (update_action_bits_for_tag(csp, tag->str)) + { + updated = 1; + } + } + + return updated; +} +#endif /********************************************************************* * @@ -822,6 +855,30 @@ int update_action_bits_for_tag(struct client_state *csp, const char *tag) /* and through all the action patterns, */ for (b = b->next; NULL != b; b = b->next) { +#ifdef FEATURE_REQUIRED_TAG + if (b->rtags) + { + /* when required tags are set, check if all required tags are matched. */ + if (0 == match_req_tag_list(b->rtags, csp->tags)) + { + /* skip when not matched. */ + continue; + } + + /* when all required tags are matched, re-check URL patterns. */ + if (url_match(b->url, csp->http)) + { + if (merge_current_action(csp->action, b->action)) + { + log_error(LOG_LEVEL_ERROR, + "Out of memory while changing action bits"); + } + /* and signal the change. */ + updated = 1; + } + } +#endif + /* skip everything but TAG patterns, */ if (!(b->url->flags & PATTERN_SPEC_TAG_PATTERN)) { @@ -1014,6 +1071,18 @@ void unload_actions_file(void *file_data) */ free_action_spec(cur->action); } +#ifdef FEATURE_REQUIRED_TAG + if ((next == NULL) || (next->rtags != cur->rtags)) + { + /* + * As the required tags might be shared, + * we can only free them if the current + * required tag is the last one, or if the + * next one is using different settings. + */ + free_req_tag_list(cur->rtags); + } +#endif /* def FEATURE_REQUIRED_TAG */ freez(cur); cur = next; } @@ -1279,7 +1348,12 @@ int load_one_actions_file(struct client_state *csp, int fileid) MODE_SETTINGS = 2, MODE_DESCRIPTION = 3, MODE_ALIAS = 4, +#ifdef FEATURE_REQUIRED_TAG + MODE_ACTIONS = 5, + MODE_REQUIRED_TAGS = 6 +#else MODE_ACTIONS = 5 +#endif } mode; FILE *fp; @@ -1291,6 +1365,10 @@ int load_one_actions_file(struct client_state *csp, int fileid) int cur_action_used = 0; struct action_alias * alias_list = NULL; unsigned long linenum = 0; +#ifdef FEATURE_REQUIRED_TAG + struct req_tag_list * cur_req_tag = NULL; + int cur_req_tag_used = 0; +#endif /* def FEATURE_REQUIRED_TAG */ mode = MODE_START_OF_FILE; if (!check_file_changed(current_actions_file[fileid], csp->config->actions_file[fileid], &fs)) @@ -1421,6 +1499,24 @@ int load_one_actions_file(struct client_state *csp, int fileid) } mode = MODE_ALIAS; } +#ifdef FEATURE_REQUIRED_TAG + else if (0 == strcmpic(start, "required")) + { + /* free old required tags */ + if (cur_req_tag) + { + if (!cur_req_tag_used) + { + free_req_tag_list(cur_req_tag); + } + cur_req_tag = NULL; + } + cur_req_tag_used = 0; + + /* set mode */ + mode = MODE_REQUIRED_TAGS; + } +#endif else { /* invalid {{something}} block */ @@ -1630,6 +1726,12 @@ int load_one_actions_file(struct client_state *csp, int fileid) csp->config->actions_file[fileid], linenum, buf); return 1; /* never get here */ } +#ifdef FEATURE_REQUIRED_TAG + perm->rtags = cur_req_tag; + if (cur_req_tag) { + cur_req_tag_used = 1; + } +#endif /* def FEATURE_REQUIRED_TAG */ /* add it to the list */ last_perm->next = perm; @@ -1644,6 +1746,31 @@ int load_one_actions_file(struct client_state *csp, int fileid) csp->config->actions_file[fileid], linenum, buf); return 1; /* never get here */ } +#ifdef FEATURE_REQUIRED_TAG + else if (mode == MODE_REQUIRED_TAGS) + { + struct req_tag_list *temp; + temp = (struct req_tag_list *)zalloc(sizeof(*temp)); + if (temp == NULL) + { + fclose(fp); + log_error(LOG_LEVEL_FATAL, + "can't load actions file '%s': out of memory", + csp->config->actions_file[fileid]); + return 1; /* never get here */ + } + if (init_req_tag_list(temp, buf) != JB_ERR_OK) + { + fclose(fp); + log_error(LOG_LEVEL_FATAL, + "can't load actions file '%s': invalid required tag configuration", + csp->config->actions_file[fileid]); + return 1; /* never get here */ + } + temp->next = cur_req_tag; + cur_req_tag = temp; + } +#endif /* def FEATURE_REQUIRED_TAG */ else { /* How did we get here? This is impossible! */ @@ -1663,6 +1790,12 @@ int load_one_actions_file(struct client_state *csp, int fileid) free_action_spec(cur_action); } free_alias_list(alias_list); +#ifdef FEATURE_REQUIRED_TAG + if (!cur_req_tag_used) + { + free_req_tag_list(cur_req_tag); + } +#endif /* def FEATURE_REQUIRED_TAG */ /* the old one is now obsolete */ if (current_actions_file[fileid]) diff --git a/actions.h b/actions.h index 618bc25..87242d1 100644 --- a/actions.h +++ b/actions.h @@ -59,6 +59,9 @@ extern void init_action(struct action_spec *dest); extern void free_action(struct action_spec *src); extern jb_err merge_actions (struct action_spec *dest, const struct action_spec *src); +#ifdef FEATURE_MANUAL_TAGGER +extern int update_action_bits_for_all_tags(struct client_state *csp); +#endif extern int update_action_bits_for_tag(struct client_state *csp, const char *tag); extern jb_err check_negative_tag_patterns(struct client_state *csp, unsigned int flag); extern jb_err copy_action (struct action_spec *dest, diff --git a/cgi.c b/cgi.c index fb663b8..fed3086 100644 --- a/cgi.c +++ b/cgi.c @@ -129,6 +129,12 @@ static const struct cgi_dispatcher cgi_dispatchers[] = { NULL, FALSE }, #endif +#ifdef FEATURE_FORWARD_CLASS + { "forward-class", + cgi_forward_class, + "View & change the forward class state", + FALSE }, +#endif /* def FEATURE_FORWARD_CLASS */ #ifdef FEATURE_CGI_EDIT_ACTIONS { "edit-actions", /* Edit the actions list */ cgi_edit_actions, @@ -593,7 +599,7 @@ static struct http_response *dispatch_known_cgi(struct client_state * csp, else { /* - * Else, modify toggle calls so that they only display + * Else, modify toggle or forward-class calls so that they only display * the status, and deny all other calls. */ if (0 == strcmp(path_copy, "toggle")) @@ -601,6 +607,11 @@ static struct http_response *dispatch_known_cgi(struct client_state * csp, unmap(param_list, "set"); err = (d->handler)(csp, rsp, param_list); } + else if (0 == strcmp(path_copy, "forward-class")) + { + map(param_list, "untrust", 1, "yes", 1); + err = (d->handler)(csp, rsp, param_list); + } else { err = cgi_error_disabled(csp, rsp); diff --git a/cgiedit.c b/cgiedit.c index d0b1106..36080e6 100644 --- a/cgiedit.c +++ b/cgiedit.c @@ -4111,6 +4111,211 @@ jb_err cgi_edit_actions_section_add(struct client_state *csp, } +#ifdef FEATURE_FORWARD_CLASS +/********************************************************************* + * + * Function : cgi_forward_class + * + * Description : CGI function that show and edit forward class state + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * 2 : rsp = http_response data structure for output + * 3 : parameters = map of cgi parameters + * + * CGI Parameters : + * : If present, how to change toggle setting: + * "enable", "disable", "toggle", or none (default). + * mini : If present, use mini reply template. + * + * Returns : JB_ERR_OK on success + * JB_ERR_MEMORY on out-of-memory + * + *********************************************************************/ +jb_err cgi_forward_class(struct client_state *csp, + struct http_response *rsp, + const struct map *parameters) +{ + struct map *exports; + struct map *section_exports; + char mode; + const char *template_name; + int i; + char *state_template; + char *state; + char *bookmarklet_template; + char *bookmarklet; + char *s; + jb_err err; + int *forward_class_state; + int forward_class[MAX_FORWARD_CLASSES]; + int is_update; + + assert(csp); + assert(rsp); + assert(parameters); + + if (NULL == (exports = default_exports(csp, "forward-class"))) + { + return JB_ERR_MEMORY; + } + + if (get_char_param(parameters, "untrust")) + { + if (get_char_param(parameters, "mini")) + { + forward_class_state = forward_class; + is_update = 1; + map_conditional(exports, "forward-class-changing", 1); + } + else + { + forward_class_state = global_forward_class_state; + is_update = 0; + map_conditional(exports, "forward-class-changing", 0); + } + } + else + { + forward_class_state = global_forward_class_state; + is_update = 1; + map_conditional(exports, "forward-class-changing", 0); + } + /* Update forward class state */ + if (is_update) + { + for (i = 0; i < MAX_FORWARD_CLASSES; i++) + { + if (csp->config->forward_class[i].name) + { + mode = get_char_param(parameters, csp->config->forward_class[i].name); + + if (mode == 'E') + { + /* Enable */ + forward_class_state[i] = 1; + } + else if (mode == 'D') + { + /* Disable */ + forward_class_state[i] = 0; + } + else if (mode == 'T') + { + /* Toggle */ + forward_class_state[i] = !global_forward_class_state[i]; + } + else + { + /* Keep */ + forward_class_state[i] = global_forward_class_state[i]; + } + } + } + } + + err = template_load(csp, &state_template, "forward-class-state", 0); + if (err) + { + if (err == JB_ERR_FILE) + { + free_map(exports); + return cgi_error_no_template(csp, rsp, "forward-class-state"); + } + return err; + } + + err = template_load(csp, &bookmarklet_template, "forward-class-bookmarklet", 0); + if (err) + { + if (err == JB_ERR_FILE) + { + free_map(exports); + free(state_template); + return cgi_error_no_template(csp, rsp, "forward-class-bookmarklet"); + } + return err; + } + + state = strdup(""); + bookmarklet = strdup(""); + for (i = 0; i < MAX_FORWARD_CLASSES; i++) + { + if (csp->config->forward_class[i].name != NULL) + { + if (err || (NULL == (section_exports = new_map()))) + { + free_map(exports); + free(state_template); + free(bookmarklet_template); + free(state); + free(bookmarklet); + return JB_ERR_MEMORY; + } + + err = map(section_exports, "forward-class-name", 1, csp->config->forward_class[i].name, 1); + if (forward_class_state[i]) + { + if (!err) err = map_block_keep(section_exports, "forward-class-enabled"); + if (!err) err = map_block_killer(section_exports, "forward-class-disabled"); + } + else + { + if (!err) err = map_block_killer(section_exports, "forward-class-enabled"); + if (!err) err = map_block_keep(section_exports, "forward-class-disabled"); + } + + if (err || (NULL == (s = strdup(state_template)))) + { + free_map(exports); + free_map(section_exports); + free(state_template); + free(bookmarklet_template); + free(state); + free(bookmarklet); + return JB_ERR_MEMORY; + } + if (!err) err = template_fill(&s, section_exports); + if (!err) err = string_join(&state, s); + if (err || (NULL == (s = strdup(bookmarklet_template)))) + { + free_map(exports); + free_map(section_exports); + free(state_template); + free(bookmarklet_template); + free(state); + free(bookmarklet); + return JB_ERR_MEMORY; + } + if (!err) err = template_fill(&s, section_exports); + free_map(section_exports); + if (!err) err = string_join(&bookmarklet, s); + } + } + freez(state_template); + freez(bookmarklet_template); + if (!err) err = map(exports, "state", 1, state, 0); + if (!err) err = map(exports, "bookmarklet", 1, bookmarklet, 0); + + if (err) + { + free_map(exports); + free(state_template); + free(bookmarklet_template); + free(state); + free(bookmarklet); + return JB_ERR_MEMORY; + } + + template_name = (get_char_param(parameters, "mini") + ? "forward-class-mini" + : "forward-class"); + + return template_fill_for_cgi(csp, template_name, exports, rsp); +} +#endif /* def FEATURE_FORWARD_CLASS */ + + /********************************************************************* * * Function : cgi_edit_actions_section_swap diff --git a/cgiedit.h b/cgiedit.h index 3b86410..855494e 100644 --- a/cgiedit.h +++ b/cgiedit.h @@ -82,6 +82,16 @@ extern jb_err cgi_edit_actions_section_add (struct client_state *csp, extern jb_err cgi_edit_actions_section_swap (struct client_state *csp, struct http_response *rsp, const struct map *parameters); +#ifdef FEATURE_FORWARD_CLASS +extern jb_err cgi_forward_class(struct client_state *csp, + struct http_response *rsp, + const struct map *parameters); +#endif /* def FEATURE_FORWARD_CLASS */ +#ifdef FEATURE_MANUAL_TAGGER +extern jb_err cgi_manual_tagger(struct client_state *csp, + struct http_response *rsp, + const struct map *parameters); +#endif /* def FEATURE_MANUAL_TAGGER */ #endif /* def FEATURE_CGI_EDIT_ACTIONS */ #ifdef FEATURE_TOGGLE extern jb_err cgi_toggle(struct client_state *csp, diff --git a/cgisimple.c b/cgisimple.c index aca2ae7..90c9621 100644 --- a/cgisimple.c +++ b/cgisimple.c @@ -62,6 +62,9 @@ #ifdef FEATURE_CLIENT_TAGS #include "client-tags.h" #endif +#ifdef FEATURE_REQUIRED_TAG +#include "requiredtag.h" +#endif static jb_err show_defines(struct map *exports); static jb_err cgi_show_file(struct client_state *csp, @@ -1757,7 +1760,11 @@ jb_err cgi_show_url_info(struct client_state *csp, for (; (b != NULL) && (matches != NULL); b = b->next) { +#ifdef FEATURE_REQUIRED_TAG + if ((b->rtags == NULL || match_req_tag_list(b->rtags, csp->tags)) && url_match(b->url, url_to_query)) +#else if (url_match(b->url, url_to_query)) +#endif { string_append(&matches, "{"); string_join (&matches, actions_to_html(csp, b->action)); @@ -2207,6 +2214,38 @@ static jb_err show_defines(struct map *exports) 0, #endif }, + { + "FEATURE_ADD_REFERER", +#ifdef FEATURE_ADD_REFERER + 1, +#else + 0, +#endif + }, + { + "FEATURE_FORWARD_CLASS", +#ifdef FEATURE_FORWARD_CLASS + 1, +#else + 0, +#endif + }, + { + "FEATURE_MANUAL_TAGGER", +#ifdef FEATURE_MANUAL_TAGGER + 1, +#else + 0, +#endif + }, + { + "FEATURE_REQUIRED_TAG", +#ifdef FEATURE_REQUIRED_TAG + 1, +#else + 0, +#endif + } }; for (i = 0; i < SZ(features); i++) diff --git a/configure.in b/configure.in index 26820ac..1730c74 100644 --- a/configure.in +++ b/configure.in @@ -82,6 +82,7 @@ VERSION_MAJOR=4 VERSION_MINOR=2 VERSION_POINT=0 CODE_STATUS="stable" +PATCHLEVEL=1 dnl Timestamp (date +%s) used by the mtree-spec target. dnl Should be updated before releases but forgetting it isn't critical. @@ -94,6 +95,7 @@ dnl ================================================================= AC_SUBST(VERSION_MAJOR) AC_SUBST(VERSION_MINOR) AC_SUBST(VERSION_POINT) +AC_SUBST(PATCHLEVEL) AC_SUBST(CODE_STATUS) AC_SUBST(SOURCE_DATE_EPOCH) @@ -101,7 +103,9 @@ dnl AC_DEFINE_UNQUOTED(VERSION_MAJOR,${VERSION_MAJOR}) AC_DEFINE_UNQUOTED(VERSION_MINOR,${VERSION_MINOR}) AC_DEFINE_UNQUOTED(VERSION_POINT,${VERSION_POINT}) -AC_DEFINE_UNQUOTED(VERSION,"${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_POINT}") +AC_DEFINE_UNQUOTED(PATCHLEVEL,${PATCHLEVEL}) +AC_DEFINE_UNQUOTED(VERSION,"${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_POINT}-y${PATCHLEVEL}") +AC_DEFINE_UNQUOTED(DOC_VERSION,"${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_POINT}") AC_DEFINE_UNQUOTED(CODE_STATUS,"${CODE_STATUS}") dnl ================================================================= @@ -1062,6 +1066,38 @@ dnl AC_ARG_ENABLE(dynamic-pcrs, dnl [ --disable-dynamic-pcrs Use the built-in, static pcrs, even if libpcrs is available], dnl [ if test $enableval = "no"; then have_pcrs=no; fi ]) +AC_ARG_ENABLE(add-referer, +[ --disable-add-referer Don't support add-referer action and extended paramters + for hide-referer action.], +[if test $enableval = yes; then + AC_DEFINE(FEATURE_ADD_REFERER) +fi], +AC_DEFINE(FEATURE_ADD_REFERER)) + +AC_ARG_ENABLE(forward-class, +[ --disable-forward-class Prevents forward class selection.], +[if test $enableval = yes; then + AC_DEFINE(FEATURE_FORWARD_CLASS) +fi], +AC_DEFINE(FEATURE_FORWARD_CLASS)) + +AC_ARG_ENABLE(manual-tagger, +[ --disable-manual-tagger Prevents manual tagger.], +[if test $enableval = yes; then + AC_DEFINE(FEATURE_MANUAL_TAGGER) +fi], +AC_DEFINE(FEATURE_MANUAL_TAGGER)) + +AC_ARG_ENABLE(required-tag, +[ --disable-required-tag Prevents required tag.], +[if test $enableval = yes; then + AC_DEFINE(FEATURE_REQUIRED_TAG) + REQUIRED_TAG_ONLY= +else + REQUIRED_TAG_ONLY=# +fi], +AC_DEFINE(FEATURE_REQUIRED_TAG)) +AC_SUBST(REQUIRED_TAG_ONLY) dnl ==================================================== dnl This check is incomplete. For mingw32 zlib is found @@ -1174,12 +1210,12 @@ if test X"$OPT_MBEDTLS" != Xno; then AC_DEFINE(FEATURE_HTTPS_INSPECTION_MBEDTLS, 1, [if mbedTLS is enabled]) AC_SUBST(FEATURE_HTTPS_INSPECTION_MBEDTLS, [1]) FEATURE_HTTPS_INSPECTION_MBEDTLS="yes" - ], [], -lmbedx509 -lmbedcrypto) + ], [], -lmbedx509 -lmbedcrypto -lbcrypt) if test "x$FEATURE_HTTPS_INSPECTION_MBEDTLS" = "xyes"; then AC_MSG_NOTICE([Detected mbedTLS. Enabling https inspection.]) - LIBS="-lmbedtls -lmbedx509 -lmbedcrypto $LIBS" + LIBS="-lmbedtls -lmbedx509 -lmbedcrypto -lbcrypt $LIBS" old_CFLAGS_nospecial="-Imbedtls/include $old_CFLAGS_nospecial" FEATURE_HTTPS_INSPECTION_ONLY= diff --git a/filters.c b/filters.c index 9a396bb..5acb002 100644 --- a/filters.c +++ b/filters.c @@ -3006,6 +3006,10 @@ void get_url_actions(struct client_state *csp, struct http_request *http) init_current_action(csp->action); +#ifdef FEATURE_MANUAL_TAGGER + update_action_bits_for_all_tags(csp); +#endif + for (i = 0; i < MAX_AF_FILES; i++) { if (((fl = csp->actions_list[i]) == NULL) || ((b = fl->f) == NULL)) @@ -3019,7 +3023,6 @@ void get_url_actions(struct client_state *csp, struct http_request *http) apply_url_actions(csp->action, http, b); #endif } - return; } @@ -3053,7 +3056,12 @@ static void apply_url_actions(struct current_action_spec *action, for (b = b->next; NULL != b; b = b->next) { +#ifdef FEATURE_REQUIRED_TAG + /* Required tag is checked at another place. */ + if (!b->rtags && url_match(b->url, http)) +#else /* def FEATURE_REQUIRED_TAG */ if (url_match(b->url, http)) +#endif /* def FEATURE_REQUIRED_TAG */ { merge_current_action(action, b->action); } @@ -3236,7 +3244,11 @@ const struct forward_spec *forward_url(struct client_state *csp, while (fwd != NULL) { +#ifdef FEATURE_FORWARD_CLASS + if (fwd->forward_class >= 0 && fwd->forward_class < MAX_FORWARD_CLASSES && csp->forward_class_state[fwd->forward_class] && url_match(fwd->url, http)) +#else if (url_match(fwd->url, http)) +#endif { return fwd; } diff --git a/jbsockets.c b/jbsockets.c index 47ac67a..9dec8f2 100644 --- a/jbsockets.c +++ b/jbsockets.c @@ -53,6 +53,10 @@ #include #include #include +#ifdef socklen_t +#undef socklen_t +#endif +#include #else @@ -126,7 +130,7 @@ static void set_no_delay_flag(int fd) #ifdef TCP_NODELAY int mi = 1; - if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &mi, sizeof(int))) + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&mi, sizeof(int))) { log_error(LOG_LEVEL_ERROR, "Failed to disable TCP coalescence for socket %d", fd); @@ -387,7 +391,7 @@ static jb_socket rfc2553_connect_to(const char *host, int portnum, struct client #endif { socklen_t optlen = sizeof(socket_error); - if (!getsockopt(fd, SOL_SOCKET, SO_ERROR, &socket_error, &optlen)) + if (!getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*)&socket_error, &optlen)) { if (!socket_error) { @@ -1386,7 +1390,7 @@ int accept_connection(struct client_state * csp, jb_socket fds[]) struct linger linger_options; linger_options.l_onoff = 1; linger_options.l_linger = 5; - if (0 != setsockopt(afd, SOL_SOCKET, SO_LINGER, &linger_options, sizeof(linger_options))) + if (0 != setsockopt(afd, SOL_SOCKET, SO_LINGER, (char*)&linger_options, sizeof(linger_options))) { log_error(LOG_LEVEL_ERROR, "Setting SO_LINGER on socket %d failed.", afd); } diff --git a/jcc.c b/jcc.c index 45d24dc..1f24cb5 100644 --- a/jcc.c +++ b/jcc.c @@ -4572,14 +4572,29 @@ static void chat(struct client_state *csp) freez(csp->headers->first->str); build_request_line(csp, fwd, &csp->headers->first->str); - if (fwd->forward_host) + if (fwd->gateway_host) { - log_error(LOG_LEVEL_CONNECT, "via [%s]:%d to: %s", - fwd->forward_host, fwd->forward_port, http->hostport); + if (fwd->forward_host) + { + log_error(LOG_LEVEL_CONNECT, "via SOCKS [%s]:%d via [%s]:%d to: %s", + fwd->gateway_host, fwd->gateway_port, fwd->forward_host, fwd->forward_port, http->hostport); + } + else + { + log_error(LOG_LEVEL_CONNECT, "via SOCKS [%s]:%d to %s", fwd->gateway_host, fwd->gateway_port, http->hostport); + } } else { - log_error(LOG_LEVEL_CONNECT, "to %s", http->hostport); + if (fwd->forward_host) + { + log_error(LOG_LEVEL_CONNECT, "via [%s]:%d to: %s", + fwd->forward_host, fwd->forward_port, http->hostport); + } + else + { + log_error(LOG_LEVEL_CONNECT, "to %s", http->hostport); + } } /* here we connect to the server, gateway, or the forwarder */ @@ -6317,6 +6332,21 @@ static void listen_loop(void) csp->flags |= CSP_FLAG_TOGGLED_ON; } +#ifdef FEATURE_FORWARD_CLASS +/* We need to set global forward class status to client associated status */ + { + int i; + for(i = 0; i < MAX_FORWARD_CLASSES; i++) { + csp->forward_class_state[i] = global_forward_class_state[i]; + } + } +#endif /* def FEATURE_FORWARD_CLASS */ + +#ifdef FEATURE_MANUAL_TAGGER +/* We need to set global manual tagger status to client associated status */ + list_duplicate(csp->tags, global_manual_tagger); +#endif /* def FEATURE_MANUAL_TAGGER */ + if (run_loader(csp)) { log_error(LOG_LEVEL_FATAL, "a loader failed - must exit"); diff --git a/loadcfg.c b/loadcfg.c index 98e8ab3..13a4fdf 100644 --- a/loadcfg.c +++ b/loadcfg.c @@ -103,6 +103,15 @@ int global_toggle_state = 1; #endif /* def FEATURE_TOGGLE */ +#ifdef FEATURE_FORWARD_CLASS +int global_forward_class_state[MAX_FORWARD_CLASSES] = { 1 }; +#endif /* def FEATURE_FORWARD_CLASS */ + +#ifdef FEATURE_MANUAL_TAGGER +struct list global_manual_tagger_[1]; +struct list* global_manual_tagger = global_manual_tagger_; +#endif /* def FEATURE_MANUAL_TAGGER */ + /* The filename of the configfile */ const char *configfile = NULL; @@ -158,6 +167,7 @@ static struct file_list *current_configfile = NULL; #define hash_enforce_blocks 1862427469U /* "enforce-blocks" */ #define hash_filterfile 250887266U /* "filterfile" */ #define hash_forward 2029845U /* "forward" */ +#define hash_forward_class 1651776168U /* "forward-class" */ #define hash_forward_socks4 3963965521U /* "forward-socks4" */ #define hash_forward_socks4a 2639958518U /* "forward-socks4a" */ #define hash_forward_socks5 3963965522U /* "forward-socks5" */ @@ -170,6 +180,7 @@ static struct file_list *current_configfile = NULL; #define hash_listen_backlog 1255655735U /* "listen-backlog" */ #define hash_logdir 422889U /* "logdir" */ #define hash_logfile 2114766U /* "logfile" */ +#define hash_manual_tagger 2633089997U /* "manual-tagger" */ #define hash_max_client_connections 3595884446U /* "max-client-connections" */ #define hash_permit_access 3587953268U /* "permit-access" */ #define hash_proxy_info_url 3903079059U /* "proxy-info-url" */ @@ -263,6 +274,21 @@ static void unload_configfile (void * data) } freez(config->logfile); +#ifdef FEATURE_FORWARD_CLASS + for (i = 0; i < MAX_FORWARD_CLASSES; i++) + { + freez(config->forward_class[i].name); + } +#endif /* def FEATURE_FORWARD_CLASS */ + +#ifdef FEATURE_MANUAL_TAGGER + for (i = 0; i < MAX_MANUAL_TAGGERS; i++) + { + freez(config->manual_tagger[i].name); + freez(config->manual_tagger[i].tag); + } +#endif /* def FEATURE_MANUAL_TAGGER */ + for (i = 0; i < MAX_AF_FILES; i++) { freez(config->actions_file_short[i]); @@ -712,6 +738,17 @@ struct configuration_spec * load_config(void) global_toggle_state = 1; #endif /* def FEATURE_TOGGLE */ +#ifdef FEATURE_FORWARD_CLASS + for(i = 0; i < MAX_FORWARD_CLASSES; i++) + { + global_forward_class_state[i] = 0; + } +#endif /* def FEATURE_FORWARD_CLASS */ + +#ifdef FEATURE_MANUAL_TAGGER + list_remove_all(global_manual_tagger); +#endif /* def FEATURE_MANUAL_TAGGER */ + fs->f = config = zalloc_or_die(sizeof(*config)); /* @@ -801,7 +838,11 @@ struct configuration_spec * load_config(void) #endif /* def FEATURE_ACL */ struct forward_spec *cur_fwd; int vec_count; +#ifdef FEATURE_FORWARD_CLASS + char *vec[4]; +#else /* def FEATURE_FORWARD_CLASS */ char *vec[3]; +#endif /* def FEATURE_FORWARD_CLASS */ unsigned int directive_hash; strlcpy(tmp, buf, sizeof(tmp)); @@ -1222,7 +1263,11 @@ struct configuration_spec * load_config(void) strlcpy(tmp, arg, sizeof(tmp)); vec_count = ssplit(tmp, " \t", vec, SZ(vec)); +#ifdef FEATURE_FORWARD_CLASS + if (vec_count != 2 && vec_count != 3) +#else /* def FEATURE_FORWARD_CLASS */ if (vec_count != 2) +#endif /* def FEATURE_FORWARD_CLASS */ { log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for forward " "directive in configuration file."); @@ -1259,12 +1304,65 @@ struct configuration_spec * load_config(void) NULL, NULL); } +#ifdef FEATURE_FORWARD_CLASS + /* Set forward class */ + if (vec_count == 3) { + cur_fwd->forward_class = atoi(vec[2]); + if(cur_fwd->forward_class > MAX_FORWARD_CLASSES) { + log_error(LOG_LEVEL_ERROR, "Forward class number for forward directive in configuration file is more than limit - the limit is %d.\n" + "(You can increase this limit by changing MAX_FORWARD_CLASSES in project.h and recompiling).", + MAX_FORWARD_CLASSES); + string_append(&config->proxy_args, + "
\nWARNING: Forward class number for forward directive" + " in configuration file is more than limit."); + break; + } + } else { + cur_fwd->forward_class = 0; + } +#endif /* def FEATURE_FORWARD_CLASS */ + /* Add to list. */ cur_fwd->next = config->forward; config->forward = cur_fwd; break; +#ifdef FEATURE_FORWARD_CLASS +/* ************************************************************************* + * forward-class class-name default-status + * *************************************************************************/ + case hash_forward_class: + i = 0; + while ((i < MAX_FORWARD_CLASSES) && (NULL != config->forward_class[i].name)) + { + i++; + } + + if (i >= MAX_FORWARD_CLASSES) + { + log_error(LOG_LEVEL_FATAL, "Too many 'forward-class' directives in config file - limit is %d.\n" + "(You can increase this limit by changing MAX_FORWARD_CLASSES in project.h and recompiling).", + MAX_FORWARD_CLASSES); + } + + strlcpy(tmp, arg, sizeof(tmp)); + vec_count = ssplit(tmp, " \t", vec, SZ(vec)); + if (vec_count != 2) + { + log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for forward class " + "directive in configuration file."); + string_append(&config->proxy_args, + "
\nWARNING: Wrong number of parameters for " + "forward class directive in configuration file."); + break; + } + + config->forward_class[i].name = strdup(vec[0]); + config->forward_class[i].state = global_forward_class_state[i] = atoi(vec[1]); + break; +#endif /* def FEATURE_FORWARD_CLASS */ + /* ************************************************************************* * forward-socks4 url-pattern socks-proxy[:port] (.|http-proxy[:port]) * *************************************************************************/ @@ -1272,7 +1370,11 @@ struct configuration_spec * load_config(void) strlcpy(tmp, arg, sizeof(tmp)); vec_count = ssplit(tmp, " \t", vec, SZ(vec)); +#ifdef FEATURE_FORWARD_CLASS + if (vec_count != 3 && vec_count != 4) +#else /* def FEATURE_FORWARD_CLASS */ if (vec_count != 3) +#endif /* def FEATURE_FORWARD_CLASS */ { log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for " "forward-socks4 directive in configuration file."); @@ -1321,6 +1423,24 @@ struct configuration_spec * load_config(void) NULL, NULL); } +#ifdef FEATURE_FORWARD_CLASS + /* Set forward class */ + if (vec_count == 4) { + cur_fwd->forward_class = atoi(vec[3]); + if(cur_fwd->forward_class > MAX_FORWARD_CLASSES) { + log_error(LOG_LEVEL_ERROR, "Forward class number for forward directive in configuration file is more than limit - the limit is %d.\n" + "(You can increase this limit by changing MAX_FORWARD_CLASSES in project.h and recompiling).", + MAX_FORWARD_CLASSES); + string_append(&config->proxy_args, + "
\nWARNING: Forward class number for forward-socks4 directive" + " in configuration file is more than limit."); + continue; + } + } else { + cur_fwd->forward_class = 0; + } +#endif /* def FEATURE_FORWARD_CLASS */ + /* Add to list. */ cur_fwd->next = config->forward; config->forward = cur_fwd; @@ -1336,7 +1456,11 @@ struct configuration_spec * load_config(void) strlcpy(tmp, arg, sizeof(tmp)); vec_count = ssplit(tmp, " \t", vec, SZ(vec)); +#ifdef FEATURE_FORWARD_CLASS + if (vec_count != 3 && vec_count != 4) +#else /* def FEATURE_FORWARD_CLASS */ if (vec_count != 3) +#endif /* def FEATURE_FORWARD_CLASS */ { log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for %s in configuration file.", @@ -1400,6 +1524,24 @@ struct configuration_spec * load_config(void) NULL, NULL); } +#ifdef FEATURE_FORWARD_CLASS + /* Set forward class */ + if (vec_count == 4) { + cur_fwd->forward_class = atoi(vec[3]); + if(cur_fwd->forward_class > MAX_FORWARD_CLASSES) { + log_error(LOG_LEVEL_ERROR, "Forward class number for forward directive in configuration file is more than limit - the limit is %d.\n" + "(You can increase this limit by changing MAX_FORWARD_CLASSES in project.h and recompiling).", + MAX_FORWARD_CLASSES); + string_append(&config->proxy_args, + "
\nWARNING: Forward class number for forward-socks4a directive" + " in configuration file is more than limit."); + continue; + } + } else { + cur_fwd->forward_class = 0; + } +#endif /* def FEATURE_FORWARD_CLASS */ + /* Add to list. */ cur_fwd->next = config->forward; config->forward = cur_fwd; @@ -1561,6 +1703,44 @@ struct configuration_spec * load_config(void) break; } +/* ************************************************************************* + * manual-tagger display-name tag default-state + * *************************************************************************/ +#ifdef FEATURE_MANUAL_TAGGER + case hash_manual_tagger : + i = 0; + while ((i < MAX_MANUAL_TAGGERS) && (NULL != config->manual_tagger[i].name)) + { + i++; + } + + if (i >= MAX_MANUAL_TAGGERS) + { + log_error(LOG_LEVEL_FATAL, "Too many 'manual-tagger' directives in config file - limit is %d.\n" + "(You can increase this limit by changing MAX_MANUAL_TAGGERS in project.h and recompiling).", + MAX_MANUAL_TAGGERS); + } + + vec_count = ssplit(arg, " \t", vec, SZ(vec)); + if (vec_count != 3) + { + log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for manual-tagger " + "directive in configuration file."); + string_append(&config->proxy_args, + "
\nWARNING: Wrong number of parameters for " + "manual-tagger directive in configuration file."); + continue; + } + + config->manual_tagger[i].name = strdup(vec[0]); + config->manual_tagger[i].tag = strdup(vec[1]); + config->manual_tagger[i].state = atoi(vec[2]); + if(config->manual_tagger[i].state) { + enlist_unique(global_manual_tagger, config->manual_tagger[i].tag, 0); + } + continue; +#endif /* def FEATURE_MANUAL_TAGGER */ + /* ************************************************************************* * permit-access source-ip[/significant-bits] [dest-ip[/significant-bits]] * *************************************************************************/ @@ -1936,6 +2116,12 @@ struct configuration_spec * load_config(void) #ifndef FEATURE_TOGGLE case hash_enable_remote_toggle: #endif /* ndef FEATURE_TOGGLE */ +#ifndef FEATURE_FORWARD_CLASS + case hash_forward_class : +#endif /* ndef FEATURE_FORWARD_CLASS */ +#ifndef FEATURE_MANUAL_TAGGER + case hash_manual_tagger : +#endif /* ndef FEATURE_MANUAL_TAGGER */ #ifndef FEATURE_ACL case hash_permit_access: #endif /* ndef FEATURE_ACL */ @@ -2156,6 +2342,17 @@ struct configuration_spec * load_config(void) g_trustfile = config->trustfile; #endif /* def FEATURE_TRUST */ +#ifdef FEATURE_FORWARD_CLASS + if(config->forward_class[0].name == NULL) { + config->forward_class[0].name = strdup("Default"); + global_forward_class_state[0] = config->forward_class[0].state = 1; + } + g_forward_class = config->forward_class; +#endif /* def FEATURE_FORWARD_CLASS */ + +#ifdef FEATURE_MANUAL_TAGGER + g_manual_tagger = config->manual_tagger; +#endif /* def FEATURE_MANUAL_TAGGER */ #endif /* defined(_WIN32) && !defined (_WIN_CONSOLE) */ /* FIXME: end kludge */ diff --git a/loadcfg.h b/loadcfg.h index ac0b0bd..a0a410d 100644 --- a/loadcfg.h +++ b/loadcfg.h @@ -47,6 +47,16 @@ struct configuration_spec; extern int global_toggle_state; #endif /* def FEATURE_TOGGLE */ +#ifdef FEATURE_FORWARD_CLASS +/* Unfortunately, project.h is required by MAX_FORWARD_CLASSES */ +#include "project.h" +extern int global_forward_class_state[MAX_FORWARD_CLASSES]; +#endif /* def FEATURE_FORWARD_CLASS */ + +#ifdef FEATURE_MANUAL_TAGGER +extern struct list* global_manual_tagger; +#endif /* def FEATURE_MANUAL_TAGGER */ + extern const char *configfile; diff --git a/parsers.c b/parsers.c index e962c14..c229d4d 100644 --- a/parsers.c +++ b/parsers.c @@ -77,7 +77,7 @@ #include "project.h" -#ifdef FEATURE_PTHREAD +#if defined(FEATURE_PTHREAD) || defined(_WIN32) #include "jcc.h" /* jcc.h is for mutex semapores only */ #endif /* def FEATURE_PTHREAD */ @@ -157,11 +157,18 @@ static jb_err server_connection_adder(struct client_state *csp); static jb_err server_proxy_connection_adder(struct client_state *csp); #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ static jb_err proxy_authentication(struct client_state *csp, char **header); +#ifdef FEATURE_ADD_REFERER +static jb_err client_referrer_adder (struct client_state *csp); +#endif /* def FEATURE_ADD_REFERER */ -static jb_err create_forged_referrer(char **header, const char *hostport); -static jb_err create_fake_referrer(char **header, const char *fake_referrer); +static jb_err create_forged_referrer(char **header, const char *hostport, int is_add); +static jb_err create_fake_referrer(char **header, const char *fake_referrer, int is_add); static jb_err handle_conditional_hide_referrer_parameter(char **header, const char *host, const int parameter_conditional_block); +#ifdef FEATURE_ADD_REFERER +static jb_err create_forged_referrer2(char **header, const char *url, int is_index, int is_add); +static jb_err create_filtered_referrer(char **header, const char *url, const char *regex, int is_add); +#endif static void create_content_length_header(unsigned long long content_length, char *header, size_t buffer_length); @@ -243,6 +250,9 @@ static const struct parsers server_patterns[] = { static const add_header_func_ptr add_client_headers[] = { client_host_adder, client_x_forwarded_for_adder, +#ifdef FEATURE_ADD_REFERER + client_referrer_adder, +#endif client_xtra_adder, client_connection_header_adder, NULL @@ -3349,16 +3359,114 @@ static jb_err client_referrer(struct client_state *csp, char **header) } else if (0 == strcmpic(parameter, "forge")) { - return create_forged_referrer(header, csp->http->hostport); + return create_forged_referrer(header, csp->http->hostport, 0 /* hide */); + } +#ifdef FEATURE_ADD_REFERER + else if (0 == strcmpic(parameter, "directory")) + { + return create_forged_referrer2(header, csp->http->url, 0 /* index */, 0 /* hide */); + } + else if (0 == strcmpic(parameter, "index")) + { + return create_forged_referrer2(header, csp->http->url, 1 /* index */, 0 /* hide */); } + else if (0 == strcmpic(parameter, "self")) + { + *header = strdup("Referer: "); + string_append(header, csp->http->url); + + log_error(LOG_LEVEL_HEADER, "Referer forged to: %s", *header); + + return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK; + } + else if ('%' == *parameter && 's' == parameter[1]) + { + return create_filtered_referrer(header, csp->http->url, parameter + 1, 0 /* hide */); + } +#endif /* def FEATURE_ADD_REFERER */ else { /* interpret parameter as user-supplied referer to fake */ - return create_fake_referrer(header, parameter); + return create_fake_referrer(header, parameter, 0 /* hide */); } } +#ifdef FEATURE_ADD_REFERER +/********************************************************************* + * + * Function : client_referrer_adder + * + * Description : Adds a Referer header field if it is missing. + * Called from `sed'. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : JB_ERR_OK on success, or + * JB_ERR_MEMORY on out-of-memory error. + * + *********************************************************************/ +jb_err client_referrer_adder(struct client_state *csp) +{ + const char *parameter; + char *header = NULL; + jb_err err = JB_ERR_OK; + + /* + * Are we adding referer? + */ + if ((csp->action->flags & ACTION_ADD_REFERER) == 0) + { + return JB_ERR_OK; + } + + parameter = csp->action->string[ACTION_STRING_ADD_REFERER]; + + if ((parameter == NULL) || (0 == strcmpic(parameter, "block")) ) + { + /* + * Blocking referer + */ + log_error(LOG_LEVEL_HEADER, "Referer crunched!"); + return JB_ERR_OK; + } + else if (0 == strcmpic(parameter, "forge")) + { + err = create_forged_referrer(&header, csp->http->hostport, 1 /* add */); + } + else if (0 == strcmpic(parameter, "directory")) + { + err = create_forged_referrer2(&header, csp->http->url, 0 /* dir */, 1 /* add */); + } + else if (0 == strcmpic(parameter, "index")) + { + err = create_forged_referrer2(&header, csp->http->url, 1 /* index */, 1 /* add */); + } + else if (0 == strcmpic(parameter, "self")) + { + header = strdup(csp->http->url); + } + else if ('%' == *parameter && 's' == parameter[1]) + { + err = create_filtered_referrer(&header, csp->http->url, parameter + 1, 1 /* add */); + } + else + { + err = create_fake_referrer(&header, parameter, 1 /* add */); + } + + if(err == JB_ERR_OK) + { + log_error(LOG_LEVEL_HEADER, "addh-unique: Referer: %s", header); + err = enlist_unique_header(csp->headers, "Referer", header); + freez(header); + } + return err; +} +#endif /* def FEATURE_ADD_REFERER */ + + /********************************************************************* * * Function : client_accept_language @@ -5015,16 +5123,18 @@ jb_err get_destination_from_headers(const struct list *headers, struct http_requ * Parameters : * 1 : header = Pointer to header pointer * 2 : hostport = Host and optionally port as string + * 3 : is_add = Boolean to signal whether add or hide + * (0 : hide / 1 : add) * * Returns : JB_ERR_OK in case of success, or * JB_ERR_MEMORY in case of memory problems. * *********************************************************************/ -static jb_err create_forged_referrer(char **header, const char *hostport) +static jb_err create_forged_referrer(char **header, const char *hostport, int is_add) { assert(NULL == *header); - *header = strdup("Referer: http://"); + *header = strdup(is_add ? "http://" : "Referer: http://"); string_append(header, hostport); string_append(header, "/"); @@ -5033,7 +5143,14 @@ static jb_err create_forged_referrer(char **header, const char *hostport) return JB_ERR_MEMORY; } - log_error(LOG_LEVEL_HEADER, "Referer forged to: %s", *header); + if (is_add) + { + log_error(LOG_LEVEL_HEADER, "addh-unique: Referer: %s", *header); + } + else + { + log_error(LOG_LEVEL_HEADER, "Referer forged to: %s", *header); + } return JB_ERR_OK; @@ -5050,29 +5167,45 @@ static jb_err create_forged_referrer(char **header, const char *hostport) * Parameters : * 1 : header = Pointer to header pointer * 2 : hosthost = Referrer to fake + * 3 : is_add = Boolean to signal whether add or hide + * (0 : hide / 1 : add) * * Returns : JB_ERR_OK in case of success, or * JB_ERR_MEMORY in case of memory problems. * *********************************************************************/ -static jb_err create_fake_referrer(char **header, const char *fake_referrer) +static jb_err create_fake_referrer(char **header, const char *fake_referrer, int is_add) { assert(NULL == *header); if ((0 != strncmpic(fake_referrer, "http://", 7)) && (0 != strncmpic(fake_referrer, "https://", 8))) { log_error(LOG_LEVEL_HEADER, - "Parameter: +hide-referrer{%s} is a bad idea, but I don't care.", fake_referrer); + "Parameter: +%s-referrer{%s} is a bad idea, but I don't care.", is_add ? "add" : "hide", fake_referrer); + } + + if(is_add) { + *header = strdup(fake_referrer); + } + else + { + *header = strdup("Referer: "); + string_append(header, fake_referrer); } - *header = strdup("Referer: "); - string_append(header, fake_referrer); if (NULL == *header) { return JB_ERR_MEMORY; } - log_error(LOG_LEVEL_HEADER, "Referer replaced with: %s", *header); + if (is_add) + { + log_error(LOG_LEVEL_HEADER, "addh-unique: Referer: %s", *header); + } + else + { + log_error(LOG_LEVEL_HEADER, "Referer replaced with: %s", *header); + } return JB_ERR_OK; @@ -5084,10 +5217,9 @@ static jb_err create_fake_referrer(char **header, const char *fake_referrer) * Function : handle_conditional_hide_referrer_parameter * * Description : Helper for client_referrer to crunch or forge - * the referrer header if the host has changed. * * Parameters : - * 1 : header = Pointer to header pointer + * 1 : header = Pointer to header pointer * 2 : host = The target host (may include the port) * 3 : parameter_conditional_block = Boolean to signal * if we're in conditional-block mode. If not set, @@ -5131,7 +5263,7 @@ static jb_err handle_conditional_hide_referrer_parameter(char **header, { freez(*header); freez(referer); - return create_forged_referrer(header, host); + return create_forged_referrer(header, host, 0 /* hide */); } } freez(referer); @@ -5169,6 +5301,141 @@ static void create_content_length_header(unsigned long long content_length, } +#ifdef FEATURE_ADD_REFERER +/********************************************************************* + * + * Function : create_forged_referrer2 + * + * Description : Helper for client_referrer to forge a referer as + * 'http://[hostname:port/dir/index.html' or + * 'http://[hostname:port/dir/' to fool stupid + * checks for in-site links + * + * Parameters : + * 1 : header = Pointer to header pointer + * 2 : url = Target URL + * 3 : is_index = Boolean to signal whether index or + * directory (0 : directory / 1 : index) + * 4 : is_add = Boolean to signal whether add or hide + * (0 : hide / 1 : add) + * + * Returns : JB_ERR_OK in case of success, or + * JB_ERR_MEMORY in case of memory problems. + * + *********************************************************************/ +static jb_err create_forged_referrer2( char **header, const char *url, int is_index, int is_add ) +{ + char *temp_url, *idx, *end; + + assert(NULL == *header); + + if(is_add) { + temp_url = strdup(url); + } + else + { + temp_url = strdup("Referer: "); + string_append(&temp_url, url); + } + + if (NULL == temp_url) + { + return JB_ERR_MEMORY; + } + + for(idx = temp_url, end = NULL; *idx != '\0' && *idx != '?'; idx++) + if(*idx == '/') end = idx; + + if(end == NULL) + { + *idx = '\0'; + string_append(&temp_url, "/"); + } + else + { + *++end = '\0'; + } + + *header = strdup(temp_url); + freez(temp_url); + if(is_index) + { + string_append(header, "index.html"); + } + + if (NULL == *header) + { + return JB_ERR_MEMORY; + } + + if (is_add) + { + log_error(LOG_LEVEL_HEADER, "addh-unique: Referer: %s", *header); + } + else + { + log_error(LOG_LEVEL_HEADER, "Referer forged to: %s", *header); + } + return JB_ERR_OK; +} + +/********************************************************************* + * + * Function : create_filtered_referrer + * + * Description : Helper for client_referrer to filter a referer by regex + * + * Parameters : + * 1 : header = Pointer to header pointer + * 2 : url = Target URL + * 3 : regex = Regular expression + * 4 : is_add = Boolean to signal whether add or hide + * (0 : hide / 1 : add) + * + * Returns : JB_ERR_OK in case of success, or + * JB_ERR_MEMORY in case of memory problems. + * + *********************************************************************/ +static jb_err create_filtered_referrer( char **header, const char *url, const char *regex, int is_add ) +{ + char *temp_url = NULL; + int hits; + + assert(NULL == *header); + assert(url); + assert(regex); + + temp_url = pcrs_execute_single_command(url, regex, &hits); + + if(is_add) + { + *header = strdup(temp_url); + } + else + { + *header = strdup("Referer: "); + string_append(header, temp_url); + } + freez(temp_url); + + if (NULL == *header) + { + return JB_ERR_MEMORY; + } + + if (is_add) + { + log_error(LOG_LEVEL_HEADER, "addh-unique: Referer: %s", *header); + } + else + { + log_error(LOG_LEVEL_HEADER, "Referer forged to: %s", *header); + } + return JB_ERR_OK; +} +#endif + + /********************************************************************* * * Function : get_expected_content_length diff --git a/project.h b/project.h index d6e2651..eb2324a 100644 --- a/project.h +++ b/project.h @@ -593,6 +593,9 @@ struct iob #define ACTION_HTTPS_INSPECTION 0x20000000UL /** Action bitmap: Turn certificates verification off */ #define ACTION_IGNORE_CERTIFICATE_ERRORS 0x40000000UL +/** Action bitmap: Add "Referer" header. (sic - follow HTTP, not English). */ +#define ACTION_ADD_REFERER 0x80000000UL + /** Action string index: How to deanimate GIFs */ #define ACTION_STRING_DEANIMATE 0 @@ -634,8 +637,10 @@ struct iob #define ACTION_STRING_LIMIT_COOKIE_LIFETIME 18 /** Action string index: how many milliseconds writes should be delayed. */ #define ACTION_STRING_DELAY_RESPONSE 19 +/** Action string index: Completion string for "Referer:" header */ +#define ACTION_STRING_ADD_REFERER 20 /** Number of string actions. */ -#define ACTION_STRING_COUNT 20 +#define ACTION_STRING_COUNT 21 /* To make the ugly hack in sed easier to understand */ @@ -716,6 +721,19 @@ struct action_spec struct list multi_add[ACTION_MULTI_COUNT][1]; }; +#ifdef FEATURE_REQUIRED_TAG +/** + * A required tag list entry. + * + * This is a linked list. + */ +struct req_tag_list +{ + regex_t *tag_regex; /**< Regex for tag matching */ + + struct req_tag_list *next; /**< The next entry in the list. */ +}; +#endif /* def FEATURE_REQUIRED_TAG */ /** * This structure is used to store action files. @@ -733,6 +751,13 @@ struct url_actions the list entry before or after the current one and can't be free'd willy nilly. */ +#ifdef FEATURE_REQUIRED_TAG + struct req_tag_list *rtags; /**< Required tags that might be shared with + the list entry before or after the current + one and can't be free'd willy nilly. */ + +#endif /* def FEATURE_REQUIRED_TAG */ + struct url_actions *next; /**< Next action section in file, or NULL. */ }; @@ -987,6 +1012,22 @@ struct reusable_connection */ #define MAX_AF_FILES 100 +#ifdef FEATURE_FORWARD_CLASS +/** + * Maximum number of forward classes. This limit is arbitrary - it's just used + * to size an array. + */ +#define MAX_FORWARD_CLASSES 10 +#endif /* def FEATURE_FORWARD_CLASS */ + +#ifdef FEATURE_MANUAL_TAGGER +/** + * Maximum number of manual taggers. This limit is arbitrary - it's just used + * to size an array. + */ +#define MAX_MANUAL_TAGGERS 10 +#endif /* def FEATURE_MANUAL_TAGGER */ + /** * Maximum number of sockets to listen to. This limit is arbitrary - it's just used * to size an array. @@ -1166,6 +1207,11 @@ struct client_state */ struct certs_chain server_certs_chain; #endif + +#ifdef FEATURE_FORWARD_CLASS + /** Forward class state associated with this client */ + int forward_class_state[MAX_FORWARD_CLASSES]; +#endif /* def FEATURE_FORWARD_CLASS */ }; /** @@ -1304,10 +1350,45 @@ struct forward_spec /** Parent HTTP proxy port. */ int forward_port; +#ifdef FEATURE_FORWARD_CLASS + /** Forward class for selection. */ + int forward_class; +#endif /* def FEATURE_FORWARD_CLASS */ + /** Next entry in the linked list. */ struct forward_spec *next; }; +#ifdef FEATURE_FORWARD_CLASS +#define FORWARD_SPEC_INITIALIZER { { URL_SPEC_INITIALIZER }, 0, NULL, 0, NULL, 0, 0, NULL } +#else /* def FEATURE_FORWARD_CLASS */ +#define FORWARD_SPEC_INITIALIZER { { URL_SPEC_INITIALIZER }, 0, NULL, 0, NULL, 0, NULL } +#endif /* def FEATURE_FORWARD_CLASS */ + +#ifdef FEATURE_FORWARD_CLASS +struct forward_class_spec +{ + /** Class name. */ + char *name; + + /** State of selection. */ + int state; +}; +#endif /* def FEATURE_FORWARD_CLASS */ + +#ifdef FEATURE_MANUAL_TAGGER +struct manual_tagger_spec +{ + /** Tagger name. */ + char *name; + + /** Tag. */ + char *tag; + + /** Default state. */ + int state; +}; +#endif /* def FEATURE_MANUAL_TAGGER */ /* Supported filter types */ enum filter_type @@ -1571,6 +1652,11 @@ struct configuration_spec /** Information about parent proxies (forwarding). */ struct forward_spec *forward; +#ifdef FEATURE_FORWARD_CLASS + /** Information about parent proxy (forwarding) classes. */ + struct forward_class_spec forward_class[MAX_FORWARD_CLASSES]; +#endif /* def FEATURE_FORWARD_CLASS */ + /** Number of retries in case a forwarded connection attempt fails */ int forwarded_connect_retries; @@ -1595,6 +1681,11 @@ struct configuration_spec /** All options from the config file, HTML-formatted. */ char *proxy_args; +#ifdef FEATURE_MANUAL_TAGGER + /** Information about manual taggers. */ + struct manual_tagger_spec manual_tagger[MAX_MANUAL_TAGGERS]; +#endif /* def FEATURE_MANUAL_TAGGER */ + /** The configuration file object. */ struct file_list *config_file_list; @@ -1650,7 +1741,7 @@ struct configuration_spec #define HOME_PAGE_URL "https://www.privoxy.org/" /** URL for the Privoxy user manual. */ -#define USER_MANUAL_URL HOME_PAGE_URL VERSION "/user-manual/" +#define USER_MANUAL_URL HOME_PAGE_URL DOC_VERSION "/user-manual/" /** Prefix for actions help links (append to USER_MANUAL_URL). */ #define ACTIONS_HELP_PREFIX "actions-file.html#" diff --git a/requiredtag.c b/requiredtag.c new file mode 100644 index 0000000..c8ff514 --- /dev/null +++ b/requiredtag.c @@ -0,0 +1,85 @@ +#include + +#include "project.h" +#include "requiredtag.h" +#include "errlog.h" +#include "miscutil.h" + +jb_err init_req_tag_list(struct req_tag_list *tags, const char* pattern) +{ + int errcode; + char ebuf[BUFFER_SIZE]; + + tags->next = NULL; + + tags->tag_regex = zalloc(sizeof(*tags->tag_regex)); + if (NULL == tags->tag_regex) + { + return JB_ERR_MEMORY; + } + + errcode = regcomp(tags->tag_regex, pattern, (REG_EXTENDED|REG_NOSUB|REG_ICASE)); + + if (errcode) + { + size_t errlen = regerror(errcode, tags->tag_regex, ebuf, sizeof(ebuf)); + if (errlen > (sizeof(ebuf) - (size_t)1)) + { + errlen = sizeof(ebuf) - (size_t)1; + } + log_error(LOG_LEVEL_ERROR, "error compiling %s : %s", + pattern, ebuf); + + return JB_ERR_PARSE; + } + + return JB_ERR_OK; +} + +void free_req_tag_list(struct req_tag_list *tags) +{ + struct req_tag_list *temp; + + if (tags == NULL) return; + + while(tags) + { + if (tags->tag_regex) + { + regfree(tags->tag_regex); + freez(tags->tag_regex); + } + temp = tags; + tags = tags->next; + freez(temp); + } +} + +static int match_req_tag(struct req_tag_list *rtags, struct list *tags) +{ + struct list_entry *tag; + + for (tag = tags->first; tag != NULL; tag = tag->next) + { + if (0 == regexec(rtags->tag_regex, tag->str, 0, NULL, 0)) + { + return 1; + } + } + return 0; +} + +int match_req_tag_list(struct req_tag_list *rtags, struct list *tags) +{ + assert(rtags); + + while(rtags) + { + if (0 == match_req_tag(rtags, tags)) + { + return 0; + } + rtags = rtags->next; + } + return 1; +} diff --git a/requiredtag.h b/requiredtag.h new file mode 100644 index 0000000..badd6de --- /dev/null +++ b/requiredtag.h @@ -0,0 +1,22 @@ +#ifndef REQUIREDTAG_H_INCLUDED +#define REQUIREDTAG_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +extern jb_err init_req_tag_list(struct req_tag_list *tags, const char* pattern); +extern void free_req_tag_list(struct req_tag_list *tags); +extern int match_req_tag_list(struct req_tag_list *rtags, struct list *tags); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ndef REQUIREDTAG_H_INCLUDED */ + +/* + Local Variables: + tab-width: 3 + end: +*/ diff --git a/templates/edit-actions-for-url b/templates/edit-actions-for-url index 465e609..a1db88d 100644 --- a/templates/edit-actions-for-url +++ b/templates/edit-actions-for-url @@ -174,6 +174,18 @@ function show_hide_referrer_opts(tf) target.style.display = (tf ? "" : "none"); } +function show_add_referrer_opts(tf) +{ + if (document.getElementById) { + target = document.getElementById("hide_referrer_opts"); + } else if (document.all) { + target = document.hide_referrer_opts; + } else { + return; + } + target.style.display = (tf ? "" : "none"); +} + function show_user_agent_opts(tf) { if (document.getElementById) { @@ -286,6 +298,52 @@ function show_limit_connect_opts(tf) add-header Adds HTTP headers. + + + + + add-referrer + Helps prevent tracking by not sending the URL of the previous web + page.  + + +   +   +   +   + +
+
+
+ (fools checks for in-site links.)
+
+ +     @@ -935,6 +993,18 @@ function show_limit_connect_opts(tf) @hide-referrer-param-conditional-forge@ id="hide_referrer_mode_conditional-forge">
+
+
+
diff --git a/templates/forward-class b/templates/forward-class new file mode 100644 index 0000000..7fa8cce --- /dev/null +++ b/templates/forward-class @@ -0,0 +1,210 @@ +########################################################## +# +# Forward class output template for Privoxy. +# +# +# USING HTML TEMPLATES: +# --------------------- +# +# Template files are written win plain HTML, with a few +# additions: +# +# - Lines that start with a '#' character like this one +# are ignored +# +# - Each item in the below list of exported symbols will +# be replaced by dynamically generated text, if they +# are enclosed in '@'-characters. E.g. The string @version@ +# will be replaced by the version number of Privoxy. +# +# - One special application of this is to make whole blocks +# of the HTML template disappear if the condition +# is not given. Simply enclose the block between the two +# strings @if-start and if--end@. The strings +# should be placed in HTML comments (), so the +# html structure won't be messed when the magic happens. +# +# USABLE SYMBOLS IN THIS TEMPLATE: +# -------------------------------- +# +# my-ip-addr: +# The IP-address that the client used to reach this proxy +# my-hostname: +# The hostname associated with my-ip-addr +# admin-address: +# The email address of the pxoxy's administrator, as configured +# in the config file +# default-cgi: +# The URL for the "main menu" builtin CGI of this proxy +# menu: +# List of
  • elements linking to the other available CGIs +# version: +# The version number of the proxy software +# code-status: +# The development status of the proxy software: "alpha", "beta", +# or "stable". +# homepage: +# The URL of the SourceForge ijbswa project, who maintains this +# software. +# +# CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: +# ------------------------------------------------------------------ +# +# unstable: +# this is an alpha or beta release of the proxy software +# have-adminaddr-info: +# An e-mail address for the local Privoxy adminstrator has +# been specified and is available through the "admin-address" +# symbol +# have-proxy-info: +# A URL for online documentation about this proxy has been +# specified and is available through the "proxy-info-url" +# symbol +# have-help-info: +# If either have-proxy-info is true or have-adminaddr-info is +# true, have-help-info is true. Used to conditionally include +# a grey box for any and all help info. +# @if-enabled-display-then@ on @else-not-enabled-display@ off @endif-enabled-display@ +# + + + + + @if-enabled-display-then@Enabled@else-not-enabled-display@Disabled@endif-enabled-display@ - Privoxy@@my-hostname@ + + + + + + + + + + + + + + + + +# This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +#include mod-title + +
    + +#include mod-unstable-warning + +
    +

    Forward class state:

    +
    + + + @state@ +
    Forward classEnabledDisabled
    +

    +
    +
    +

    Bookmarklets

    +

    Here are some bookmarklets to allow you to easily access a + "mini" version of this page. They are known to work with MS + Internet Explorer, Netscape and Mozilla, but should work equally + well in other browsers which support JavaScript. They are designed + to run directly from your bookmarks - not by clicking the + links below (although that will work for testing). +

    +

    To save them, right-click the link and choose + "Add to Favorites" (IE) or "Add Bookmark" (Netscape). You + will get a warning that the bookmark "may not be safe" - just + click OK. Then you can run the Bookmarklet directly from your + favourites/bookmarks. For even faster access, you can put + them on the "Links" bar (IE) or the "Personal Toolbar" + (Netscape), and run them with a single click. +

    + +
    + + + @bookmarklet@ +
    Forward classEnabledDisabledToggleKeep
    +
    +

    Privoxy - Forward class

    + +

    + Credit: The site which gave us the general idea for these + bookmarklets is www.bookmarklets.com. + They have more information about them. +

    +
    +

    More Privoxy:

    + +
    + +#include mod-support-and-service + +
    + +#include mod-local-help + +
    +

    Valid HTML 4.01 Strict

    +
    + + + diff --git a/templates/forward-class-bookmarklet b/templates/forward-class-bookmarklet new file mode 100644 index 0000000..34778de --- /dev/null +++ b/templates/forward-class-bookmarklet @@ -0,0 +1 @@ +@forward-class-name@ diff --git a/templates/forward-class-mini b/templates/forward-class-mini new file mode 100644 index 0000000..6e6720a --- /dev/null +++ b/templates/forward-class-mini @@ -0,0 +1,95 @@ +########################################################## +# +# Toggle Output template for Privoxy. +# +# +# USING HTML TEMPLATES: +# --------------------- +# +# Template files are written win plain HTML, with a few +# additions: +# +# - Lines that start with a '#' character like this one +# are ignored +# +# - Each item in the below list of exported symbols will +# be replaced by dynamically generated text, if they +# are enclosed in '@'-characters. E.g. The string @version@ +# will be replaced by the version number of Privoxy. +# +# - One special application of this is to make whole blocks +# of the HTML template disappear if the condition +# is not given. Simply enclose the block between the two +# strings @if-start and if--end@. The strings +# should be placed in HTML comments (), so the +# html structure won't be messed when the magic happens. +# +# USABLE SYMBOLS IN THIS TEMPLATE: +# -------------------------------- +# +# my-ip-addr: +# The IP-address that the client used to reach this proxy +# my-hostname: +# The hostname associated with my-ip-addr +# admin-address: +# The email address of the pxoxy's administrator, as configured +# in the config file +# default-cgi: +# The URL for the "main menu" builtin CGI of this proxy +# menu: +# List of
  • elements linking to the other available CGIs +# version: +# The version number of the proxy software +# code-status: +# The development status of the proxy software: "alpha", "beta", +# or "stable". +# homepage: +# The URL of the SourceForge ijbswa project, who maintains this +# software. +# +# CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: +# ------------------------------------------------------------------ +# +# unstable: +# this is an alpha or beta release of the proxy software +# have-adminaddr-info: +# An e-mail address for the local Privoxy adminstrator has +# been specified and is available through the "admin-address" +# symbol +# have-proxy-info: +# A URL for online documentation about this proxy has been +# specified and is available through the "proxy-info-url" +# symbol +# have-help-info: +# If either have-proxy-info is true or have-adminaddr-info is +# true, have-help-info is true. Used to conditionally include +# a grey box for any and all help info. +# @if-enabled-display-then@ on @else-not-enabled-display@ off @endif-enabled-display@ +# + + + + + Forward class - Privoxy@@my-hostname@ + + + + + + + + +
    Privoxy Forward class state @if-forward-class-changing-then@will be changed to@else-not-forward-class-changing@is@endif-forward-class-changing@ +
    + + + + @state@ +
    Forward classEnabledDisabled

    + + + +
    +
    + + diff --git a/templates/forward-class-state b/templates/forward-class-state new file mode 100644 index 0000000..7ac110d --- /dev/null +++ b/templates/forward-class-state @@ -0,0 +1 @@ +@forward-class-name@ diff --git a/templates/show-status b/templates/show-status index 6685928..b85de0a 100644 --- a/templates/show-status +++ b/templates/show-status @@ -402,6 +402,26 @@ Allows to decompress Zstandard-compressed content for filtering. Requires external zstd library. + + FEATURE_ADD_REFERER + @if-FEATURE_ADD_REFERER-then@ Yes @else-not-FEATURE_ADD_REFERER@ No @endif-FEATURE_ADD_REFERER@ + Enables add-referer action and extended parameters for hide-referer action. + + + FEATURE_FORWARD_CLASS + @if-FEATURE_FORWARD_CLASS-then@ Yes @else-not-FEATURE_FORWARD_CLASS@ No @endif-FEATURE_FORWARD_CLASS@ + Enables forward class selection. + + + FEATURE_MANUAL_TAGGER + @if-FEATURE_MANUAL_TAGGER-then@ Yes @else-not-FEATURE_MANUAL_TAGGER@ No @endif-FEATURE_MANUAL_TAGGER@ + Enables manual tagger. + + + FEATURE_REQUIRED_TAG + @if-FEATURE_REQUIRED_TAG-then@ Yes @else-not-FEATURE_REQUIRED_TAG@ No @endif-FEATURE_REQUIRED_TAG@ + Enables required tag. + diff --git a/w32.rc b/w32.rc index ab38a44..af0cde1 100644 --- a/w32.rc +++ b/w32.rc @@ -91,8 +91,8 @@ IDI_OFF ICON DISCARDABLE "icons/off.ico" #ifndef _MAC VS_VERSION_INFO VERSIONINFO - FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_POINT,0 - PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_POINT,0 + FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_POINT,PATCHLEVEL + PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_POINT,PATCHLEVEL FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -147,6 +147,20 @@ BEGIN MENUITEM "&Trust list", ID_TOOLS_EDITTRUST #endif /* def FEATURE_TRUST */ END +#ifdef FEATURE_MANUAL_TAGGER + MENUITEM SEPARATOR + POPUP "&Tag.." + BEGIN + MENUITEM SEPARATOR + END +#endif /* def FEATURE_MANUAL_TAGGER */ +#ifdef FEATURE_FORWARD_CLASS + MENUITEM SEPARATOR + POPUP "&Forward.." + BEGIN + MENUITEM SEPARATOR + END +#endif /* FEATURE_FORWARD_CLASS */ MENUITEM SEPARATOR #ifdef FEATURE_TOGGLE MENUITEM "&Enable", ID_TOGGLE_ENABLED, CHECKED @@ -180,6 +194,20 @@ BEGIN MENUITEM "&Enable", ID_TOGGLE_ENABLED, CHECKED MENUITEM SEPARATOR #endif /* def FEATURE_TOGGLE */ +#ifdef FEATURE_MANUAL_TAGGER + POPUP "&Tag.." + BEGIN + MENUITEM SEPARATOR + END + MENUITEM SEPARATOR +#endif /* def FEATURE_MANUAL_TAGGER */ +#ifdef FEATURE_FORWARD_CLASS + POPUP "&Forward.." + BEGIN + MENUITEM SEPARATOR + END + MENUITEM SEPARATOR +#endif /* def FEATURE_FORWARD_CLASS */ MENUITEM "Edit Main &Configuration", ID_TOOLS_EDITCONFIG MENUITEM "Edit &Default Actions", ID_TOOLS_EDITDEFAULTACTIONS MENUITEM "Edit &User Actions", ID_TOOLS_EDITUSERACTIONS diff --git a/w32log.c b/w32log.c index c7e3540..8d83230 100644 --- a/w32log.c +++ b/w32log.c @@ -53,6 +53,9 @@ #include "miscutil.h" #include "errlog.h" #include "loadcfg.h" +#ifdef FEATURE_MANUAL_TAGGER +#include "list.h" +#endif #ifndef _WIN_CONSOLE /* entire file */ @@ -131,6 +134,12 @@ const char * g_user_filterfile = NULL; #ifdef FEATURE_TRUST const char * g_trustfile = NULL; #endif /* def FEATURE_TRUST */ +#ifdef FEATURE_FORWARD_CLASS +struct forward_class_spec* g_forward_class = NULL; +#endif /* def FEATURE_FORWARD_CLASS */ +#ifdef FEATURE_MANUAL_TAGGER +struct manual_tagger_spec* g_manual_tagger = NULL; +#endif /* def FEATURE_MANUAL_TAGGER */ /* FIXME: end kludge */ @@ -217,6 +226,10 @@ static int g_nAnimFrame; static BOOL g_bClipPending = FALSE; static int g_nRichEditVersion = 0; +#if defined(FEATURE_FORWARD_CLASS) || defined(FEATURE_MANUAL_TAGGER) +static UINT g_uQueryMessage; +#endif + /* * Private functions */ @@ -230,9 +243,16 @@ static void LogClipBuffer(void); static void LogCreatePatternMatchingBuffers(void); static void LogDestroyPatternMatchingBuffers(void); static int LogPutStringNoMatch(const char *pszText, int style); +#ifdef FEATURE_MANUAL_TAGGER +static HMENU GetTagSubMenu(HMENU hmenu); +static void SetTagSubMenu(HMENU hmenu); +#endif /* def FEATURE_MANUAL_TAGGER */ +#ifdef FEATURE_FORWARD_CLASS +static HMENU GetForwardSubMenu(HMENU hmenu); +static void SetForwardSubMenu(HMENU hmenu); +#endif /* def FEATURE_FORWARD_CLASS */ static void SetIdleIcon(void); - /********************************************************************* * * Function : InitLogWindow @@ -268,6 +288,10 @@ BOOL InitLogWindow(void) /* Create a critical section to protect multi-threaded access to certain things */ InitializeCriticalSection(&g_criticalsection); +#if defined(FEATURE_FORWARD_CLASS) || defined(FEATURE_MANUAL_TAGGER) + g_uQueryMessage = RegisterWindowMessage("PrivoxyEnhancedQueryMessage"); +#endif + return TRUE; } @@ -999,6 +1023,25 @@ void OnLogCommand(int nCommand) break; default: +#ifdef FEATURE_FORWARD_CLASS + if(ID_FORWARD_CLASS <= nCommand && nCommand < ID_FORWARD_CLASS + MAX_FORWARD_CLASSES) { + global_forward_class_state[nCommand - ID_FORWARD_CLASS] = ! global_forward_class_state[nCommand - ID_FORWARD_CLASS]; + break; + } +#endif /* def FEATURE_FORWARD_CLASS */ +#ifdef FEATURE_MANUAL_TAGGER + if(ID_MANUAL_TAGGER <= nCommand && nCommand < ID_MANUAL_TAGGER + MAX_MANUAL_TAGGERS) { + if(list_contains_item(global_manual_tagger, g_manual_tagger[nCommand - ID_MANUAL_TAGGER].tag)) + { + list_remove_item(global_manual_tagger, g_manual_tagger[nCommand - ID_MANUAL_TAGGER].tag); + } + else + { + enlist_unique(global_manual_tagger, g_manual_tagger[nCommand - ID_MANUAL_TAGGER].tag, 0); + } + break; + } +#endif /* def FEATURE_MANUAL_TAGGER */ /* DO NOTHING */ break; } @@ -1041,6 +1084,15 @@ void OnLogInitMenu(HMENU hmenu) #endif /* def FEATURE_TOGGLE */ CheckMenuItem(hmenu, ID_TOGGLE_SHOWWINDOW, MF_BYCOMMAND | (g_bShowLogWindow ? MF_CHECKED : MF_UNCHECKED)); +#ifdef FEATURE_MANUAL_TAGGER + /* Set manual tagger sub menu */ + SetTagSubMenu(hmenu); +#endif /* def FEATURE_MANUAL_TAGGER */ +#ifdef FEATURE_FORWARD_CLASS + /* Set forward class sub menu */ + SetForwardSubMenu(hmenu); +#endif /* def FEATURE_FORWARD_CLASS */ + } @@ -1087,6 +1139,226 @@ void OnLogTimer(int nTimer) } +#if defined(FEATURE_FORWARD_CLASS) || defined(FEATURE_MANUAL_TAGGER) +/********************************************************************* + * + * Function : OnLogQuery + * + * Description : Handler for PrivoxyEnhancedQueryMessage messages. + * + * Parameters : + * 1 : nID = query target and command + * (ID_FORWARD_CLASS or ID_MANUAL_TAGGER) + + * 0 = query max count (defult 10) + * 1 = get status + * 2 = set status by lParam + * 2 : uParam = lParam for query type 2 + * + * Returns : if query type = 0, + * returns MAX_FORWARD_CLASSES or MAX_MANUAL_TAGGERS + * if query type = 1, + * returns packed bits flag of global_forward_class_state + * or global_manual_tagger + * LSB represents ID 0 + * if query type = 2, returns set state + * + *********************************************************************/ +LRESULT OnLogQuery(int nID, unsigned int uParam) +{ + int i; + unsigned int uResult = 0; + + switch (nID) + { + /* forward class */ /* assuming MAX_FORWARD_CLASSES <= 32 */ + case ID_FORWARD_CLASS: + return MAX_FORWARD_CLASSES; + + case ID_FORWARD_CLASS + 1: /* get */ + for (i = 0; i < MAX_FORWARD_CLASSES; i++) + { + if (global_forward_class_state[i]) + { + uResult |= (1U << i); + } + } + return uResult; + + case ID_FORWARD_CLASS + 2: /* set */ + for (i = 0; i < MAX_FORWARD_CLASSES; i++) + { + global_forward_class_state[i] = (uParam & 1U); + if (global_forward_class_state[i]) + { + uResult |= (1U << i); + } + uParam >>= 1; + } + return uResult; + + /* manual tagger */ /* assuming MAX_MANUAL_TAGGERS <= 32 */ + case ID_MANUAL_TAGGER: + return MAX_MANUAL_TAGGERS; + + case ID_MANUAL_TAGGER + 1: /* get */ + for (i = 0; i < MAX_MANUAL_TAGGERS; i++) + { + if (g_manual_tagger[i].name + && list_contains_item(global_manual_tagger, g_manual_tagger[i].tag)) + { + uResult |= (1U << i); + } + } + return uResult; + + case ID_MANUAL_TAGGER + 2: /* set */ + list_remove_all(global_manual_tagger); + for (i = 0; i < MAX_MANUAL_TAGGERS; i++) + { + if (g_manual_tagger[i].name && (uParam & 1u)) + { + enlist_unique(global_manual_tagger, g_manual_tagger[i].tag, 0); + uResult |= (1U << i); + } + uParam >>= 1; + } + return uResult; + } + return 0; // not reached +} +#endif + + +#ifdef FEATURE_MANUAL_TAGGER +/********************************************************************* + * + * Function : GetTagSubMenu + * + * Description : Extract tag sub menu + * + * Parameters : + * 1 : hmenu = Handle of menu containing tag sub menu + * + * Returns : Handle of tag sub menu + * + *********************************************************************/ +HMENU GetTagSubMenu(HMENU hmenu) +{ + char szItemName[256]; + int nMax = GetMenuItemCount(hmenu), i; + MENUITEMINFO mii = { sizeof(MENUITEMINFO), MIIM_SUBMENU | MIIM_STRING }; + mii.dwTypeData = szItemName; + mii.cch = sizeof(szItemName); + + for(i = 0; i < nMax; i++) { + GetMenuItemInfo(hmenu, i, TRUE, &mii); + if(mii.hSubMenu && lstrcmp("&Options", mii.dwTypeData) == 0) { + return GetTagSubMenu(mii.hSubMenu); + } + if(mii.hSubMenu && lstrcmp("&Tag..", mii.dwTypeData) == 0) { + return mii.hSubMenu; + } + mii.cch = sizeof(szItemName); + } + return NULL; +} + +/********************************************************************* + * + * Function : SetTagSubMenu + * + * Description : Add items into tag sub menu + * + * Parameters : + * 1 : hmenu = Handle of menu containing tag sub menu + * + * Returns : N/A + * + *********************************************************************/ +void SetTagSubMenu(HMENU hmenu) +{ + int nMax, i; + hmenu = GetTagSubMenu(hmenu); + + if(hmenu == NULL) return; + + nMax = GetMenuItemCount(hmenu); + for(i = 0; i < nMax; i++) { + RemoveMenu(hmenu, 0, MF_BYPOSITION); + } + + for(i = 0; g_manual_tagger[i].name != NULL && i < MAX_MANUAL_TAGGERS; i++) { + AppendMenu(hmenu, MF_STRING | (list_contains_item(global_manual_tagger, g_manual_tagger[i].tag) ? MF_CHECKED : MF_UNCHECKED), ID_MANUAL_TAGGER + i, g_manual_tagger[i].name); + } +} +#endif /* def FEATURE_MANUAL_TAGGER */ + + +#ifdef FEATURE_FORWARD_CLASS +/********************************************************************* + * + * Function : GetForwardSubMenu + * + * Description : Extract forward sub menu + * + * Parameters : + * 1 : hmenu = Handle of menu containing forward sub menu + * + * Returns : Handle of forward sub menu + * + *********************************************************************/ +HMENU GetForwardSubMenu(HMENU hmenu) +{ + char szItemName[256]; + int nMax = GetMenuItemCount(hmenu), i; + MENUITEMINFO mii = { sizeof(MENUITEMINFO), MIIM_SUBMENU | MIIM_STRING }; + mii.dwTypeData = szItemName; + mii.cch = sizeof(szItemName); + + for(i = 0; i < nMax; i++) { + GetMenuItemInfo(hmenu, i, TRUE, &mii); + if(mii.hSubMenu && lstrcmp("&Options", mii.dwTypeData) == 0) { + return GetForwardSubMenu(mii.hSubMenu); + } + if(mii.hSubMenu && lstrcmp("&Forward..", mii.dwTypeData) == 0) { + return mii.hSubMenu; + } + mii.cch = sizeof(szItemName); + } + return NULL; +} + + +/********************************************************************* + * + * Function : SetForwardSubMenu + * + * Description : Add items into forward sub menu + * + * Parameters : + * 1 : hmenu = Handle of menu containing forward sub menu + * + * Returns : N/A + * + *********************************************************************/ +void SetForwardSubMenu(HMENU hmenu) +{ + int nMax, i; + hmenu = GetForwardSubMenu(hmenu); + + if(hmenu == NULL) return; + + nMax = GetMenuItemCount(hmenu); + for(i = 0; i < nMax; i++) { + RemoveMenu(hmenu, 0, MF_BYPOSITION); + } + for(i = 0; g_forward_class[i].name != NULL && i < MAX_FORWARD_CLASSES; i++) { + AppendMenu(hmenu, MF_STRING | (global_forward_class_state[i] ? MF_CHECKED : MF_UNCHECKED), ID_FORWARD_CLASS + i, g_forward_class[i].name); + } +} +#endif /* def FEATURE_FORWARD_CLASS */ + + /********************************************************************* * * Function : SetIdleIcon @@ -1233,6 +1505,12 @@ LRESULT CALLBACK LogWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPara } break; } +#if defined(FEATURE_FORWARD_CLASS) || defined(FEATURE_MANUAL_TAGGER) + if (uMsg == g_uQueryMessage) + { + return OnLogQuery(wParam, lParam); + } +#endif return DefWindowProc(hwnd, uMsg, wParam, lParam); diff --git a/w32log.h b/w32log.h index 1c80c09..df485f9 100644 --- a/w32log.h +++ b/w32log.h @@ -73,6 +73,12 @@ extern const char * g_user_filterfile; #ifdef FEATURE_TRUST extern const char * g_trustfile; #endif /* def FEATURE_TRUST */ +#ifdef FEATURE_FORWARD_CLASS +extern struct forward_class_spec* g_forward_class; +#endif /* def FEATURE_FORWARD_CLASS */ +#ifdef FEATURE_MANUAL_TAGGER +extern struct manual_tagger_spec* g_manual_tagger; +#endif /* def FEATURE_MANUAL_TAGGER */ /* FIXME: end kludge */ diff --git a/w32res.h b/w32res.h index 90ff6b9..9aeaa52 100644 --- a/w32res.h +++ b/w32res.h @@ -83,6 +83,16 @@ #endif /* ndef W32RES_H_INCLUDED */ +#ifdef FEATURE_FORWARD_CLASS +/* ID until ID_FORWARD_CLASS + MAX_FORWARD_CLASSES - 1 are reserved. */ +#define ID_FORWARD_CLASS 6000 +#endif /* def FEATURE_FORWARD_CLASS */ + +#ifdef FEATURE_MANUAL_TAGGER +/* ID until ID_MANUAL_TAGGER + MAX_MANUAL_TAGGERS - 1 are reserved. */ +#define ID_MANUAL_TAGGER 7000 +#endif /* def FEATURE_MANUAL_TAGGER */ + /* Local Variables: tab-width: 3