From f47685c861d493154e81ff23f02fb27edb2dcba4 Mon Sep 17 00:00:00 2001 From: Robert James Kaes Date: Thu, 6 Jun 2002 20:32:30 +0000 Subject: A bunch of changes from Petr Lampa that add transparent proxy support to tinyproxy. The additional code is in process_request(), but Petr also had to change around some of the other functions (like process_client_headers and handle_connection.) Note: Right now this code has not been tested, but it is believed to work. To enable run ./configure --enable-transparent-proxy --- src/reqs.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 98 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/reqs.c b/src/reqs.c index 9f3398e..aca329e 100644 --- a/src/reqs.c +++ b/src/reqs.c @@ -1,4 +1,4 @@ -/* $Id: reqs.c,v 1.81 2002-05-31 18:09:09 rjkaes Exp $ +/* $Id: reqs.c,v 1.82 2002-06-06 20:32:30 rjkaes Exp $ * * This is where all the work in tinyproxy is actually done. Incoming * connections have a new child created for them. The child then @@ -11,6 +11,7 @@ * Copyright (C) 1998 Steven Young * Copyright (C) 1999-2002 Robert James Kaes (rjkaes@flarenet.com) * Copyright (C) 2000 Chris Lightfoot (chris@ex-parrot.com) + * Copyright (C) 2002 Petr Lampa (lampa@fit.vutbr.cz) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -300,7 +301,7 @@ send_ssl_response(struct conn_s *connptr) * build a new request line. Finally connect to the remote server. */ static struct request_s * -process_request(struct conn_s *connptr) +process_request(struct conn_s *connptr, hashmap_t hashofheaders) { char *url; struct request_s *request; @@ -397,6 +398,61 @@ process_request(struct conn_s *connptr) connptr->connect_method = TRUE; } else { +#ifdef TRANSPARENT_PROXY + /* + * This section of code is used for the transparent proxy + * option. You will need to configure your firewall to + * redirect all connections for HTTP traffic to tinyproxy + * for this to work properly. + * + * This code was written by Petr Lampa + */ + int length; + char *data; + length = hashmap_entry_by_key(hashofheaders, "host", (void **)&data); + if (length <= 0) { + struct sockaddr_in dest_addr; + + if (getsockname(connptr->client_fd, (struct sockaddr *)&dest_addr, &length) < 0) { + log_message(LOG_ERR, + "process_request: cannot get destination IP for %d", + connptr->client_fd); + indicate_http_error(connptr, 400, "Bad Request. Unknown destination."); + safefree(url); + free_request_struct(request); + return NULL; + } + request->host = safemalloc(17); + strcpy(request->host, inet_ntoa(dest_addr.sin_addr)); + request->port = ntohs(dest_addr.sin_port); + request->path = safemalloc(strlen(url) + 1); + strcpy(request->path, url); + log_message(LOG_INFO, + "process_request: trans IP %s http://%s:%d%s for %d", + request->method, request->host, request->port, request->path, connptr->client_fd); + } else { + request->host = safemalloc(length+1); + if (sscanf(data, "%[^:]:%hu", request->host, &request->port) != 2) { + strcpy(request->host, data); + request->port = 80; + } + request->path = safemalloc(strlen(url) + 1); + strcpy(request->path, url); + log_message(LOG_INFO, + "process_request: trans Host %s http://%s:%d%s for %d", + request->method, request->host, request->port, request->path, connptr->client_fd); + } + if (config.ipAddr && + strcmp(request->host, config.ipAddr) == 0) { + log_message(LOG_ERR, + "process_request: destination IP is localhost %d", + connptr->client_fd); + indicate_http_error(connptr, 400, "Bad Request. Bad destination."); + safefree(url); + free_request_struct(request); + return NULL; + } +#else log_message(LOG_ERR, "process_request: Unknown URL type on file descriptor %d", connptr->client_fd); @@ -406,6 +462,7 @@ process_request(struct conn_s *connptr) free_request_struct(request); return NULL; +#endif } #ifdef FILTER_ENABLE @@ -730,38 +787,26 @@ write_via_header(int fd, hashmap_t hashofheaders, * - rjkaes */ static int -process_client_headers(struct conn_s *connptr) +process_client_headers(struct conn_s *connptr, hashmap_t hashofheaders) { static char *skipheaders[] = { "host", "keep-alive", "proxy-authenticate", "proxy-authorization", + "proxy-connection", "te", "trailers", "transfer-encoding", "upgrade" }; int i; - hashmap_t hashofheaders; hashmap_iter iter; long content_length = -1; int ret; char *data, *header; - hashofheaders = hashmap_create(HEADER_BUCKETS); - if (!hashofheaders) - return -1; - - /* - * Get all the headers from the client in a big hash. - */ - if (get_all_headers(connptr->client_fd, hashofheaders) < 0) { - log_message(LOG_WARNING, "Could not retrieve all the headers from the client"); - goto ERROR_EXIT; - } - /* * Don't send headers if there's already an error, if the request was * a stats request, or if this was a CONNECT method (unless upstream @@ -770,7 +815,6 @@ process_client_headers(struct conn_s *connptr) if (connptr->server_fd == -1 || connptr->show_stats || (connptr->connect_method && !UPSTREAM_CONFIGURED())) { log_message(LOG_INFO, "Not sending client headers to remote machine"); - hashmap_delete(hashofheaders); return 0; } @@ -841,17 +885,11 @@ process_client_headers(struct conn_s *connptr) * Spin here pulling the data from the client. */ PULL_CLIENT_DATA: - hashmap_delete(hashofheaders); - if (content_length > 0) return pull_client_data(connptr, (unsigned long int) content_length); else return ret; - - ERROR_EXIT: - hashmap_delete(hashofheaders); - return -1; } /* @@ -865,6 +903,7 @@ process_server_headers(struct conn_s *connptr) "keep-alive", "proxy-authenticate", "proxy-authorization", + "proxy-connection", "transfer-encoding", }; @@ -1219,6 +1258,7 @@ handle_connection(int fd) { struct conn_s *connptr; struct request_s *request = NULL; + hashmap_t hashofheaders = NULL; char peer_ipaddr[PEER_IP_LENGTH]; char peer_string[PEER_STRING_LENGTH]; @@ -1238,7 +1278,9 @@ handle_connection(int fd) update_stats(STAT_DENIED); indicate_http_error(connptr, 403, "You do not have authorization for using this service."); - goto send_error; + send_http_error_message(connptr); + destroy_conn(connptr); + return; } if (TUNNEL_CONFIGURED()) { @@ -1251,23 +1293,50 @@ handle_connection(int fd) internal_proxy: if (read_request_line(connptr) < 0) { update_stats(STAT_BADCONN); + indicate_http_error(connptr, 408, + "Server timeout waiting for the HTTP request from the client."); + send_http_error_message(connptr); destroy_conn(connptr); return; } - request = process_request(connptr); + /* + * The "hashofheaders" store the client's headers. + */ + if (!(hashofheaders = hashmap_create(HEADER_BUCKETS))) { + update_stats(STAT_BADCONN); + indicate_http_error(connptr, 503, HTTP503ERROR); + send_http_error_message(connptr); + destroy_conn(connptr); + return; + } + + /* + * Get all the headers from the client in a big hash. + */ + if (get_all_headers(connptr->client_fd, hashofheaders) < 0) { + log_message(LOG_WARNING, "Could not retrieve all the headers from the client"); + hashmap_delete(hashofheaders); + update_stats(STAT_BADCONN); + destroy_conn(connptr); + return; + } + + request = process_request(connptr, hashofheaders); if (!request) { if (!connptr->error_string && !connptr->show_stats) { update_stats(STAT_BADCONN); destroy_conn(connptr); + hashmap_delete(hashofheaders); return; } goto send_error; } if (UPSTREAM_CONFIGURED()) { - if (connect_to_upstream(connptr, request) < 0) + if (connect_to_upstream(connptr, request) < 0) { goto send_error; + } } else { connptr->server_fd = opensock(request->host, request->port); if (connptr->server_fd < 0) { @@ -1286,13 +1355,15 @@ handle_connection(int fd) send_error: free_request_struct(request); - if (process_client_headers(connptr) < 0) { + if (process_client_headers(connptr, hashofheaders) < 0) { update_stats(STAT_BADCONN); if (!connptr->error_string) { + hashmap_delete(hashofheaders); destroy_conn(connptr); return; } } + hashmap_delete(hashofheaders); if (connptr->error_string) { send_http_error_message(connptr); -- cgit v1.2.3