X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=filters.c;h=c5d8d6ea4dc5bae180ec69f1b518166203f32f7d;hp=9c9ae2e622ff9cf83482458ce5eaab0c2c23f76a;hb=e14447d0f0ebc27b37232fbb8d68a232d2a553a0;hpb=f08e3d0ab8d466e41e4f7be61dce8e4f8b869d79 diff --git a/filters.c b/filters.c index 9c9ae2e6..c5d8d6ea 100644 --- a/filters.c +++ b/filters.c @@ -1,4 +1,4 @@ -const char filters_rcs[] = "$Id: filters.c,v 1.99 2008/02/03 13:57:58 fabiankeil Exp $"; +const char filters_rcs[] = "$Id: filters.c,v 1.115 2009/04/17 11:29:18 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/filters.c,v $ @@ -10,10 +10,10 @@ const char filters_rcs[] = "$Id: filters.c,v 1.99 2008/02/03 13:57:58 fabiankeil * `filter_popups', `forward_url', 'redirect_url', * `ij_untrusted_url', `intercept_url', `pcrs_filter_respose', * `ijb_send_banner', `trust_url', `gif_deanimate_response', - * `jpeg_inspect_response', `execute_single_pcrs_command', - * `rewrite_url', `get_last_url' + * `execute_single_pcrs_command', `rewrite_url', + * `get_last_url' * - * Copyright : Written by and Copyright (C) 2001, 2004-2007 the SourceForge + * Copyright : Written by and Copyright (C) 2001, 2004-2008 the SourceForge * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written @@ -40,6 +40,64 @@ const char filters_rcs[] = "$Id: filters.c,v 1.99 2008/02/03 13:57:58 fabiankeil * * Revisions : * $Log: filters.c,v $ + * Revision 1.115 2009/04/17 11:29:18 fabiankeil + * Compile fix for BSD libc. + * + * Revision 1.114 2009/04/17 11:27:49 fabiankeil + * Petr Pisar's privoxy-3.0.12-ipv6-3.diff. + * + * Revision 1.113 2009/03/08 14:19:23 fabiankeil + * Fix justified (but harmless) compiler warnings + * on platforms where sizeof(int) < sizeof(long). + * + * Revision 1.112 2009/03/01 18:28:23 fabiankeil + * Help clang understand that we aren't dereferencing + * NULL pointers here. + * + * Revision 1.111 2008/12/04 18:13:46 fabiankeil + * Fix a cparser warning. + * + * Revision 1.110 2008/11/10 16:40:25 fabiankeil + * Fix a gcc44 warning. + * + * Revision 1.109 2008/11/08 15:48:41 fabiankeil + * Mention actual values when complaining about + * the chunk size exceeding the buffer size. + * + * Revision 1.108 2008/05/21 15:35:08 fabiankeil + * - Mark csp as immutable for block_acl(). + * - Remove an obsolete complaint about filter_popups(). + * + * Revision 1.107 2008/05/04 17:52:56 fabiankeil + * Adjust parse_http_url() call to new prototype. + * + * Revision 1.106 2008/05/03 16:40:44 fabiankeil + * Change content_filters_enabled()'s parameter from + * csp->action to action so it can be also used in the + * CGI code. Don't bother checking if there are filters + * loaded, as that's somewhat besides the point. + * + * Revision 1.105 2008/03/28 15:13:39 fabiankeil + * Remove inspect-jpegs action. + * + * Revision 1.104 2008/03/27 18:27:24 fabiankeil + * Remove kill-popups action. + * + * Revision 1.103 2008/03/06 16:33:45 fabiankeil + * If limit-connect isn't used, don't limit CONNECT requests to port 443. + * + * Revision 1.102 2008/03/01 14:00:44 fabiankeil + * Let the block action take the reason for the block + * as argument and show it on the "blocked" page. + * + * Revision 1.101 2008/02/23 16:57:12 fabiankeil + * Rename url_actions() to get_url_actions() and let it + * use the standard parameter ordering. + * + * Revision 1.100 2008/02/23 16:33:43 fabiankeil + * Let forward_url() use the standard parameter ordering + * and mark its second parameter immutable. + * * Revision 1.99 2008/02/03 13:57:58 fabiankeil * Add SOCKS5 support for forward-override{}. * @@ -613,6 +671,11 @@ const char filters_rcs[] = "$Id: filters.c,v 1.99 2008/02/03 13:57:58 fabiankeil #include #include +#ifdef HAVE_GETADDRINFO +#include +#include +#endif /* def HAVE_GETADDRINFO */ + #ifndef _WIN32 #ifndef __OS2__ #include @@ -660,6 +723,151 @@ static jb_err remove_chunked_transfer_coding(char *buffer, size_t *size); static jb_err prepare_for_filtering(struct client_state *csp); #ifdef FEATURE_ACL +#ifdef HAVE_GETADDRINFO +/********************************************************************* + * + * Function : sockaddr_storage_to_ip + * + * Description : Access internal structure of sockaddr_storage + * + * Parameters : + * 1 : addr = socket address + * 2 : ip = IP address as array of octets in network order + * (it points into addr) + * 3 : len = length of IP address in octets + * 4 : port = port number in network order; + * + * Returns : 0 = no errror; -1 otherwise. + * + *********************************************************************/ +int sockaddr_storage_to_ip(const struct sockaddr_storage *addr, uint8_t **ip, + unsigned int *len, in_port_t **port) +{ + if (NULL == addr) + { + return(-1); + } + + switch (addr->ss_family) + { + case AF_INET: + if (NULL != len) + { + *len = 4; + } + if (NULL != ip) + { + *ip = (uint8_t *) + &(((struct sockaddr_in *)addr)->sin_addr.s_addr); + } + if (NULL != port) + { + *port = &((struct sockaddr_in *)addr)->sin_port; + } + break; + + case AF_INET6: + if (NULL != len) + { + *len = 16; + } + if (NULL != ip) + { + *ip = ((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr; + } + if (NULL != port) + { + *port = &((struct sockaddr_in6 *)addr)->sin6_port; + } + break; + + default: + /* Unsupported address family */ + return(-1); + } + + return(0); +} + + +/********************************************************************* + * + * Function : match_sockaddr + * + * Description : Check whether address matches network (IP address and port) + * + * Parameters : + * 1 : network = socket address of subnework + * 2 : netmask = network mask as socket address + * 3 : address = checked socket address against given network + * + * Returns : 0 = doesn't match; 1 = does match + * + *********************************************************************/ +int match_sockaddr(const struct sockaddr_storage *network, + const struct sockaddr_storage *netmask, + const struct sockaddr_storage *address) +{ + uint8_t *network_addr, *netmask_addr, *address_addr; + unsigned int addr_len; + in_port_t *network_port, *netmask_port, *address_port; + int i; + + if (network->ss_family != netmask->ss_family) + { + /* This should never happen */ + log_error(LOG_LEVEL_ERROR, + "Internal error at %s:%llu: network and netmask differ in family", + __FILE__, __LINE__); + return 0; + } + + sockaddr_storage_to_ip(network, &network_addr, &addr_len, &network_port); + sockaddr_storage_to_ip(netmask, &netmask_addr, NULL, &netmask_port); + sockaddr_storage_to_ip(address, &address_addr, NULL, &address_port); + + /* Check for family */ + if ((network->ss_family == AF_INET) && (address->ss_family == AF_INET6) + && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)address_addr)) + { + /* Map AF_INET6 V4MAPPED address into AF_INET */ + address_addr += 12; + addr_len = 4; + } + else if ((network->ss_family == AF_INET6) && (address->ss_family == AF_INET) + && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)network_addr)) + { + /* Map AF_INET6 V4MAPPED network into AF_INET */ + network_addr += 12; + netmask_addr += 12; + addr_len = 4; + } + else if (network->ss_family != address->ss_family) + { + return 0; + } + + /* XXX: Port check is signaled in netmask */ + if (*netmask_port && *network_port != *address_port) + { + return 0; + } + + /* TODO: Optimize by checking by words insted of octets */ + for (i = 0; (i < addr_len) && netmask_addr[i]; i++) + { + if ((network_addr[i] & netmask_addr[i]) != + (address_addr[i] & netmask_addr[i])) + { + return 0; + } + } + + return 1; +} +#endif /* def HAVE_GETADDRINFO */ + + /********************************************************************* * * Function : block_acl @@ -676,7 +884,7 @@ static jb_err prepare_for_filtering(struct client_state *csp); * Returns : 0 = FALSE (don't block) and 1 = TRUE (do block) * *********************************************************************/ -int block_acl(struct access_control_addr *dst, struct client_state *csp) +int block_acl(const struct access_control_addr *dst, const struct client_state *csp) { struct access_control_list *acl = csp->config->acl; @@ -689,7 +897,13 @@ int block_acl(struct access_control_addr *dst, struct client_state *csp) /* search the list */ while (acl != NULL) { - if ((csp->ip_addr_long & acl->src->mask) == acl->src->addr) + if ( +#ifdef HAVE_GETADDRINFO + match_sockaddr(&acl->src->addr, &acl->src->mask, &csp->tcp_addr) +#else + (csp->ip_addr_long & acl->src->mask) == acl->src->addr +#endif + ) { if (dst == NULL) { @@ -699,8 +913,23 @@ int block_acl(struct access_control_addr *dst, struct client_state *csp) return(0); } } - else if ( ((dst->addr & acl->dst->mask) == acl->dst->addr) - && ((dst->port == acl->dst->port) || (acl->dst->port == 0))) + else if ( +#ifdef HAVE_GETADDRINFO + /* + * XXX: An undefined acl->dst is full of zeros and should be + * considered a wildcard address. sockaddr_storage_to_ip() + * fails on such destinations because of unknown sa_familly + * (glibc only?). However this test is not portable. + * + * So, we signal the acl->dst is wildcard in wildcard_dst. + */ + acl->wildcard_dst || + match_sockaddr(&acl->dst->addr, &acl->dst->mask, &dst->addr) +#else + ((dst->addr & acl->dst->mask) == acl->dst->addr) + && ((dst->port == acl->dst->port) || (acl->dst->port == 0)) +#endif + ) { if (acl->action == ACL_PERMIT) { @@ -736,12 +965,24 @@ int block_acl(struct access_control_addr *dst, struct client_state *csp) int acl_addr(const char *aspec, struct access_control_addr *aca) { int i, masklength; +#ifdef HAVE_GETADDRINFO + struct addrinfo hints, *result; + uint8_t *mask_data; + in_port_t *mask_port; + unsigned int addr_len; +#else long port; +#endif /* def HAVE_GETADDRINFO */ char *p; char *acl_spec = NULL; +#ifdef HAVE_GETADDRINFO + /* XXX: Depend on ai_family */ + masklength = 128; +#else masklength = 32; port = 0; +#endif /* * Use a temporary acl spec copy so we can log @@ -765,13 +1006,53 @@ int acl_addr(const char *aspec, struct access_control_addr *aca) masklength = atoi(p); } - if ((masklength < 0) || (masklength > 32)) + if ((masklength < 0) || +#ifdef HAVE_GETADDRINFO + (masklength > 128) +#else + (masklength > 32) +#endif + ) { freez(acl_spec); return(-1); } - if ((p = strchr(acl_spec, ':')) != NULL) + if ((*acl_spec == '[') && (NULL != (p = strchr(acl_spec, ']')))) + { + *p = '\0'; + memmove(acl_spec, acl_spec + 1, (size_t)(p - acl_spec)); + + if (*++p != ':') + { + p = NULL; + } + } + else + { + p = strchr(acl_spec, ':'); + } + +#ifdef HAVE_GETADDRINFO + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + i = getaddrinfo(acl_spec, ((p) ? ++p : NULL), &hints, &result); + freez(acl_spec); + + if (i != 0) + { + log_error(LOG_LEVEL_ERROR, "Can not resolve [%s]:%s: %s", + acl_spec, p, gai_strerror(i)); + return(-1); + } + + /* TODO: Allow multihomed hostnames */ + memcpy(&(aca->addr), result->ai_addr, result->ai_addrlen); + freeaddrinfo(result); +#else + if (p != NULL) { char *endptr; @@ -795,18 +1076,67 @@ int acl_addr(const char *aspec, struct access_control_addr *aca) /* XXX: This will be logged as parse error. */ return(-1); } +#endif /* def HAVE_GETADDRINFO */ /* build the netmask */ +#ifdef HAVE_GETADDRINFO + /* Clip masklength according to current family. */ + if ((aca->addr.ss_family == AF_INET) && (masklength > 32)) + { + masklength = 32; + } + + aca->mask.ss_family = aca->addr.ss_family; + if (sockaddr_storage_to_ip(&aca->mask, &mask_data, &addr_len, &mask_port)) + { + return(-1); + } + + if (p) + { + /* ACL contains a port number, check ports in the future. */ + *mask_port = 1; + } + + /* + * XXX: This could be optimized to operate on whole words instead + * of octets (128-bit CPU could do it in one iteration). + */ + /* + * Octets after prefix can be ommitted because of + * previous initialization to zeros. + */ + for (i = 0; (i < addr_len) && masklength; i++) + { + if (masklength >= 8) + { + mask_data[i] = 0xFF; + masklength -= 8; + } + else + { + /* + * XXX: This assumes MSB of octet is on the left side. + * This should be true for all architectures or solved + * by the link layer. + */ + mask_data[i] = ~((1 << (8 - masklength)) - 1); + masklength = 0; + } + } + +#else aca->mask = 0; for (i=1; i <= masklength ; i++) { - aca->mask |= (1 << (32 - i)); + aca->mask |= (1U << (32 - i)); } /* now mask off the host portion of the ip address * (i.e. save on the network portion of the address). */ aca->addr = aca->addr & aca->mask; +#endif /* def HAVE_GETADDRINFO */ return(0); @@ -814,6 +1144,28 @@ int acl_addr(const char *aspec, struct access_control_addr *aca) #endif /* def FEATURE_ACL */ +/********************************************************************* + * + * Function : connect_port_is_forbidden + * + * Description : Check to see if CONNECT requests to the destination + * port of this request are forbidden. The check is + * independend of the actual request method. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : True if yes, false otherwise. + * + *********************************************************************/ +int connect_port_is_forbidden(const struct client_state *csp) +{ + return ((csp->action->flags & ACTION_LIMIT_CONNECT) && + !match_portlist(csp->action->string[ACTION_STRING_LIMIT_CONNECT], + csp->http->port)); +} + + /********************************************************************* * * Function : block_url @@ -1046,7 +1398,20 @@ struct http_response *block_url(struct client_state *csp) if (!err) err = map(exports, "hostport", 1, html_encode(csp->http->hostport), 0); if (!err) err = map(exports, "path", 1, html_encode(csp->http->path), 0); if (!err) err = map(exports, "path-ue", 1, url_encode(csp->http->path), 0); - + if (!err) + { + const char *block_reason; + if (csp->action->string[ACTION_STRING_BLOCK] != NULL) + { + block_reason = csp->action->string[ACTION_STRING_BLOCK]; + } + else + { + assert(connect_port_is_forbidden(csp)); + block_reason = "Forbidden CONNECT port."; + } + err = map(exports, "block-reason", 1, html_encode(block_reason), 0); + } if (err) { free_map(exports); @@ -1679,7 +2044,7 @@ int is_untrusted_url(const struct client_state *csp) /* * If not, do we maybe trust its referrer? */ - err = parse_http_url(referer, rhttp, csp); + err = parse_http_url(referer, rhttp, REQUIRE_PROTOCOL); if (err) { return 1; @@ -1712,7 +2077,7 @@ int is_untrusted_url(const struct client_state *csp) /* since this path points into a user's home space * be sure to include this spec in the trustfile. */ - int path_len = path_end - path; /* save offset */ + long path_len = path_end - path; /* save offset */ path = strdup(path); /* Copy string */ if (path != NULL) { @@ -2007,68 +2372,6 @@ static char *gif_deanimate_response(struct client_state *csp) } -/********************************************************************* - * - * Function : jpeg_inspect_response - * - * Description : - * - * Parameters : - * 1 : csp = Current client state (buffers, headers, etc...) - * - * Returns : a pointer to the (newly allocated) modified buffer - * or NULL in case something went wrong. - * - *********************************************************************/ -static char *jpeg_inspect_response(struct client_state *csp) -{ - struct binbuffer *in = NULL; - struct binbuffer *out = NULL; - char *p = NULL; - size_t size; - - size = (size_t)(csp->iob->eod - csp->iob->cur); - - if (NULL == (in = (struct binbuffer *)zalloc(sizeof *in ))) - { - log_error(LOG_LEVEL_DEANIMATE, "failed! (jpeg no mem 1)"); - return NULL; - } - - if (NULL == (out = (struct binbuffer *)zalloc(sizeof *out))) - { - log_error(LOG_LEVEL_DEANIMATE, "failed! (jpeg no mem 2)"); - return NULL; - } - - in->buffer = csp->iob->cur; - in->size = size; - - /* - * Calling jpeg_inspect has the side-effect of creating and - * modifying the image buffer of "out" directly. - */ - if (jpeg_inspect(in, out)) - { - log_error(LOG_LEVEL_DEANIMATE, "failed! (jpeg parsing)"); - freez(in); - buf_free(out); - return(NULL); - - } - else - { - csp->content_length = out->offset; - csp->flags |= CSP_FLAG_MODIFIED; - p = out->buffer; - freez(in); - freez(out); - return(p); - } - -} - - /********************************************************************* * * Function : get_filter_function @@ -2076,12 +2379,6 @@ static char *jpeg_inspect_response(struct client_state *csp) * Description : Decides which content filter function has * to be applied (if any). * - * XXX: Doesn't handle filter_popups() - * because of the different prototype. Probably - * we should ditch filter_popups() anyway, it's - * even less reliable than popup blocking based - * on pcrs filters. - * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * @@ -2140,11 +2437,6 @@ filter_function_ptr get_filter_function(struct client_state *csp) { filter_function = gif_deanimate_response; } - else if ((csp->content_type & CT_JPEG) && - (csp->action->flags & ACTION_JPEG_INSPECT)) - { - filter_function = jpeg_inspect_response; - } return filter_function; } @@ -2182,7 +2474,7 @@ static jb_err remove_chunked_transfer_coding(char *buffer, size_t *size) return JB_ERR_PARSE; } - while (chunksize > 0) + while (chunksize > 0U) { if (NULL == (from_p = strstr(from_p, "\r\n"))) { @@ -2192,7 +2484,9 @@ static jb_err remove_chunked_transfer_coding(char *buffer, size_t *size) if ((newsize += chunksize) >= *size) { - log_error(LOG_LEVEL_ERROR, "Chunksize exceeds buffer in \"chunked\" transfer coding"); + log_error(LOG_LEVEL_ERROR, + "Chunk size %d exceeds buffer size %d in \"chunked\" transfer coding", + chunksize, *size); return JB_ERR_PARSE; } from_p += 2; @@ -2340,19 +2634,18 @@ char *execute_content_filter(struct client_state *csp, filter_function_ptr conte /********************************************************************* * - * Function : url_actions + * Function : get_url_actions * * Description : Gets the actions for this URL. * * Parameters : - * 1 : http = http_request request for blocked URLs - * 2 : csp = Current client state (buffers, headers, etc...) + * 1 : csp = Current client state (buffers, headers, etc...) + * 2 : http = http_request request for blocked URLs * * Returns : N/A * *********************************************************************/ -void url_actions(struct http_request *http, - struct client_state *csp) +void get_url_actions(struct client_state *csp, struct http_request *http) { struct file_list *fl; struct url_actions *b; @@ -2471,6 +2764,7 @@ const static struct forward_spec *get_forward_override_settings(struct client_st log_error(LOG_LEVEL_FATAL, "can't allocate memory for forward-override{%s}", forward_override_line); /* Never get here - LOG_LEVEL_FATAL causes program exit */ + return NULL; } vec_count = ssplit(forward_settings, " \t", vec, SZ(vec), 1, 1); @@ -2510,7 +2804,7 @@ const static struct forward_spec *get_forward_override_settings(struct client_st if (NULL != (socks_proxy = strchr(fwd->gateway_host, ':'))) { *socks_proxy++ = '\0'; - fwd->gateway_port = strtol(socks_proxy, NULL, 0); + fwd->gateway_port = (int)strtol(socks_proxy, NULL, 0); } if (fwd->gateway_port <= 0) @@ -2537,7 +2831,7 @@ const static struct forward_spec *get_forward_override_settings(struct client_st if (NULL != (http_parent = strchr(fwd->forward_host, ':'))) { *http_parent++ = '\0'; - fwd->forward_port = strtol(http_parent, NULL, 0); + fwd->forward_port = (int)strtol(http_parent, NULL, 0); } if (fwd->forward_port <= 0) @@ -2675,16 +2969,15 @@ struct http_response *direct_response(struct client_state *csp) * enabled for the current request. * * Parameters : - * 1 : csp = Current client state (buffers, headers, etc...) + * 1 : action = Action spec to check. * * Returns : TRUE for yes, FALSE otherwise * *********************************************************************/ -inline int content_filters_enabled(const struct client_state *csp) +int content_filters_enabled(const struct current_action_spec *action) { - return (((csp->rlist != NULL) && - (!list_is_empty(csp->action->multi[ACTION_MULTI_FILTER]))) || - (csp->action->flags & (ACTION_DEANIMATE|ACTION_JPEG_INSPECT|ACTION_NO_POPUPS))); + return ((action->flags & ACTION_DEANIMATE) || + !list_is_empty(action->multi[ACTION_MULTI_FILTER])); } /*