X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=parsers.c;h=11d28c71dc12e2d3c9cbf76b846d9d72a3dbca34;hp=b8f636d3d090ecc7873c96f20971f2ebf5a4850c;hb=54debef090db214715953499571b8d7ec77980db;hpb=81ebaf495849d8057d6c9a595edda17699261b12 diff --git a/parsers.c b/parsers.c index b8f636d3..11d28c71 100644 --- a/parsers.c +++ b/parsers.c @@ -1,12 +1,11 @@ -const char parsers_rcs[] = "$Id: parsers.c,v 1.309 2016/04/30 10:28:36 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/parsers.c,v $ * * Purpose : Declares functions to parse/crunch headers and pages. * - * Copyright : Written by and Copyright (C) 2001-2016 the - * Privoxy team. http://www.privoxy.org/ + * Copyright : Written by and Copyright (C) 2001-2020 the + * Privoxy team. https://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and @@ -90,8 +89,6 @@ const char parsers_rcs[] = "$Id: parsers.c,v 1.309 2016/04/30 10:28:36 fabiankei #include "strptime.h" #endif -const char parsers_h_rcs[] = PARSERS_H_VERSION; - static char *get_header_line(struct iob *iob); static jb_err scan_headers(struct client_state *csp); static jb_err header_tagger(struct client_state *csp, char *header); @@ -252,13 +249,14 @@ static const add_header_func_ptr add_server_headers[] = { /********************************************************************* * - * Function : flush_socket + * Function : flush_iob * * Description : Write any pending "buffered" content. * * Parameters : * 1 : fd = file descriptor of the socket to read * 2 : iob = The I/O buffer to flush, usually csp->iob. + * 3 : delay = Number of milliseconds to delay the writes * * Returns : On success, the number of bytes written are returned (zero * indicates nothing was written). On error, -1 is returned, @@ -268,7 +266,7 @@ static const add_header_func_ptr add_server_headers[] = { * file, the results are not portable. * *********************************************************************/ -long flush_socket(jb_socket fd, struct iob *iob) +long flush_iob(jb_socket fd, struct iob *iob, unsigned int delay) { long len = iob->eod - iob->cur; @@ -277,7 +275,7 @@ long flush_socket(jb_socket fd, struct iob *iob) return(0); } - if (write_socket(fd, iob->cur, (size_t)len)) + if (write_socket_delayed(fd, iob->cur, (size_t)len, delay)) { return(-1); } @@ -421,8 +419,13 @@ jb_err decompress_iob(struct client_state *csp) int status; /* return status of the inflate() call */ z_stream zstr; /* used by calls to zlib */ +#ifdef FUZZ + assert(csp->iob->cur - csp->iob->buf >= 0); + assert(csp->iob->eod - csp->iob->cur >= 0); +#else assert(csp->iob->cur - csp->iob->buf > 0); assert(csp->iob->eod - csp->iob->cur > 0); +#endif bufsize = csp->iob->size; skip_size = (size_t)(csp->iob->cur - csp->iob->buf); @@ -630,6 +633,7 @@ jb_err decompress_iob(struct client_state *csp) if (bufsize >= csp->config->buffer_limit) { log_error(LOG_LEVEL_ERROR, "Buffer limit reached while decompressing iob"); + freez(buf); return JB_ERR_MEMORY; } @@ -718,7 +722,7 @@ jb_err decompress_iob(struct client_state *csp) * Make sure the new uncompressed iob obeys some minimal * consistency conditions. */ - if ((csp->iob->buf < csp->iob->cur) + if ((csp->iob->buf <= csp->iob->cur) && (csp->iob->cur <= csp->iob->eod) && (csp->iob->eod <= csp->iob->buf + csp->iob->size)) { @@ -1182,6 +1186,65 @@ jb_err sed(struct client_state *csp, int filter_server_headers) } +#ifdef FEATURE_HTTPS_INSPECTION +/********************************************************************* + * + * Function : sed_https + * + * Description : add, delete or modify lines in the HTTPS client + * header streams. Wrapper around sed(). + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : JB_ERR_OK in case off success, or + * JB_ERR_MEMORY on some out-of-memory errors, or + * JB_ERR_PARSE in case of fatal parse errors. + * + *********************************************************************/ +jb_err sed_https(struct client_state *csp) +{ + jb_err err; + struct list headers; + + /* + * Temporarily replace csp->headers with csp->https_headers + * to trick sed() into filtering the https headers. + */ + headers.first = csp->headers->first; + headers.last = csp->headers->last; + csp->headers->first = csp->https_headers->first; + csp->headers->last = csp->https_headers->last; + + /* + * Start with fresh tags. Already existing tags may + * be set again. This is necessary to overrule + * URL-based patterns. + */ + destroy_list(csp->tags); + + /* + * We want client header filters and taggers + * so temporarily remove the flag. + */ + csp->flags &= ~CSP_FLAG_CLIENT_HEADER_PARSING_DONE; + err = sed(csp, FILTER_CLIENT_HEADERS); + csp->flags |= CSP_FLAG_CLIENT_HEADER_PARSING_DONE; + + /* + * Update the last header which may have changed + * due to header additions, + */ + csp->https_headers->last = csp->headers->last; + + csp->headers->first = headers.first; + csp->headers->last = headers.last; + + return err; +} +#endif /* def FEATURE_HTTPS_INSPECTION */ + + /********************************************************************* * * Function : update_server_headers @@ -1811,7 +1874,9 @@ static jb_err client_keep_alive(struct client_state *csp, char **header) static jb_err get_content_length(const char *header_value, unsigned long long *length) { #ifdef _WIN32 - assert(sizeof(unsigned long long) > 4); +#if SIZEOF_LONG_LONG < 8 +#error sizeof(unsigned long long) too small +#endif if (1 != sscanf(header_value, "%I64u", length)) #else if (1 != sscanf(header_value, "%llu", length)) @@ -1893,7 +1958,7 @@ static jb_err client_connection(struct client_state *csp, char **header) if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING) && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)) { - if (!strcmpic(csp->http->ver, "HTTP/1.1")) + if (!strcmpic(csp->http->version, "HTTP/1.1")) { log_error(LOG_LEVEL_HEADER, "Removing \'%s\' to imply keep-alive.", *header); @@ -2394,7 +2459,7 @@ static jb_err server_content_encoding(struct client_state *csp, char **header) * * Description : Remove the Content-Encoding header if the * decompression was successful and the content - * has been modifed. + * has been modified. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) @@ -2709,20 +2774,24 @@ static jb_err server_last_modified(struct client_state *csp, char **header) #elif defined(MUTEX_LOCKS_AVAILABLE) privoxy_mutex_lock(&gmtime_mutex); timeptr = gmtime(&last_modified); - privoxy_mutex_unlock(&gmtime_mutex); #else timeptr = gmtime(&last_modified); #endif if ((NULL == timeptr) || !strftime(newheader, sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr)) { +#if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE) + privoxy_mutex_unlock(&gmtime_mutex); +#endif log_error(LOG_LEVEL_ERROR, "Randomizing '%s' failed. Crunching the header without replacement.", *header); freez(*header); return JB_ERR_OK; } - +#if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE) + privoxy_mutex_unlock(&gmtime_mutex); +#endif freez(*header); *header = strdup("Last-Modified: "); string_append(header, newheader); @@ -3413,20 +3482,24 @@ static jb_err client_if_modified_since(struct client_state *csp, char **header) #elif defined(MUTEX_LOCKS_AVAILABLE) privoxy_mutex_lock(&gmtime_mutex); timeptr = gmtime(&tm); - privoxy_mutex_unlock(&gmtime_mutex); #else timeptr = gmtime(&tm); #endif if ((NULL == timeptr) || !strftime(newheader, sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr)) { +#if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE) + privoxy_mutex_unlock(&gmtime_mutex); +#endif log_error(LOG_LEVEL_ERROR, "Randomizing '%s' failed. Crunching the header without replacement.", *header); freez(*header); return JB_ERR_OK; } - +#if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE) + privoxy_mutex_unlock(&gmtime_mutex); +#endif freez(*header); *header = strdup("If-Modified-Since: "); string_append(header, newheader); @@ -3834,7 +3907,7 @@ static jb_err client_connection_header_adder(struct client_state *csp) #ifdef FEATURE_CONNECTION_KEEP_ALIVE if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE) && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED) - && !strcmpic(csp->http->ver, "HTTP/1.1")) + && !strcmpic(csp->http->version, "HTTP/1.1")) { csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; return JB_ERR_OK; @@ -3974,17 +4047,22 @@ static void add_cookie_expiry_date(char **cookie, time_t lifetime) #elif defined(MUTEX_LOCKS_AVAILABLE) privoxy_mutex_lock(&gmtime_mutex); timeptr = gmtime(&expiry_date); - privoxy_mutex_unlock(&gmtime_mutex); #else timeptr = gmtime(&expiry_date); #endif if (NULL == timeptr) { +#if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE) + privoxy_mutex_unlock(&gmtime_mutex); +#endif log_error(LOG_LEVEL_FATAL, "Failed to get the time in add_cooky_expiry_date()"); } strftime(tmp, sizeof(tmp), "; expires=%a, %d-%b-%Y %H:%M:%S GMT", timeptr); +#if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE) + privoxy_mutex_unlock(&gmtime_mutex); +#endif if (JB_ERR_OK != string_append(cookie, tmp)) { log_error(LOG_LEVEL_FATAL, "Out of memory in add_cooky_expiry()"); @@ -4424,8 +4502,6 @@ jb_err get_destination_from_headers(const struct list *headers, struct http_requ char *p; char *host; - assert(!http->ssl); - host = get_header_value(headers, "Host:"); if (NULL == host) @@ -4478,7 +4554,7 @@ jb_err get_destination_from_headers(const struct list *headers, struct http_requ string_append(&http->cmd, " "); string_append(&http->cmd, http->url); string_append(&http->cmd, " "); - string_append(&http->cmd, http->ver); + string_append(&http->cmd, http->version); if (http->cmd == NULL) { return JB_ERR_MEMORY; @@ -4489,6 +4565,88 @@ jb_err get_destination_from_headers(const struct list *headers, struct http_requ } +#ifdef FEATURE_HTTPS_INSPECTION +/********************************************************************* + * + * Function : get_destination_from_https_headers + * + * Description : Parse the previously encrypted "Host:" header to + * get the request's destination. + * + * Parameters : + * 1 : headers = List of headers (one of them hopefully being + * the "Host:" header) + * 2 : http = storage for the result (host, port and hostport). + * + * Returns : JB_ERR_MEMORY (or terminates) in case of memory problems, + * JB_ERR_PARSE if the host header couldn't be found, + * JB_ERR_OK otherwise. + * + *********************************************************************/ +jb_err get_destination_from_https_headers(const struct list *headers, struct http_request *http) +{ + char *q; + char *p; + char *host; + + host = get_header_value(headers, "Host:"); + + if (NULL == host) + { + log_error(LOG_LEVEL_ERROR, "No \"Host:\" header found."); + return JB_ERR_PARSE; + } + + p = strdup_or_die(host); + chomp(p); + q = strdup_or_die(p); + + freez(http->hostport); + http->hostport = p; + freez(http->host); + http->host = q; + q = strchr(http->host, ':'); + if (q != NULL) + { + /* Terminate hostname and evaluate port string */ + *q++ = '\0'; + http->port = atoi(q); + } + else + { + http->port = 443; + } + + /* Rebuild request URL */ + freez(http->url); + http->url = strdup_or_die(http->path); + + log_error(LOG_LEVEL_HEADER, + "Destination extracted from \"Host\" header. New request URL: %s", + http->url); + + /* + * Regenerate request line in "proxy format" + * to make rewrites more convenient. + */ + assert(http->cmd != NULL); + freez(http->cmd); + http->cmd = strdup_or_die(http->gpc); + string_append(&http->cmd, " "); + string_append(&http->cmd, http->url); + string_append(&http->cmd, " "); + string_append(&http->cmd, http->version); + if (http->cmd == NULL) + { + return JB_ERR_MEMORY; + } + + return JB_ERR_OK; + +} +#endif /* def FEATURE_HTTPS_INSPECTION */ + + /********************************************************************* * * Function : create_forged_referrer @@ -4639,7 +4797,14 @@ static jb_err handle_conditional_hide_referrer_parameter(char **header, static void create_content_length_header(unsigned long long content_length, char *header, size_t buffer_length) { +#ifdef _WIN32 +#if SIZEOF_LONG_LONG < 8 +#error sizeof(unsigned long long) too small +#endif + snprintf(header, buffer_length, "Content-Length: %I64u", content_length); +#else snprintf(header, buffer_length, "Content-Length: %llu", content_length); +#endif }