From 18df4910a43e8f1b0d9d10df37236fabf0ba8508 Mon Sep 17 00:00:00 2001 From: Robert James Kaes Date: Tue, 27 Apr 2004 18:53:14 +0000 Subject: Added the "BindSame" configure directive from Oswald Buddenhagen. This allows tinyproxy to respond to a request bound to the same interface that the request came in on. As Oswald explains: "attached is a patch that adds the BindSame option. it causes binding an outgoing connection to the ip address of the respective incoming connection. that way one can simulate an entire proxy farm with a single instance of tinyproxy on a multi-homed machine." Cool. --- src/conns.c | 8 ++++++-- src/conns.h | 10 ++++++++-- src/grammar.y | 9 +++++++-- src/reqs.c | 29 +++++++++++++++++++---------- src/scanner.l | 3 ++- src/sock.c | 48 ++++++++++++++++++++++++++++++++++++++---------- src/sock.h | 9 +++++---- src/tinyproxy.h | 3 ++- 8 files changed, 87 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/conns.c b/src/conns.c index c7091a3..c94b245 100644 --- a/src/conns.c +++ b/src/conns.c @@ -1,4 +1,4 @@ -/* $Id: conns.c,v 1.21 2004-02-13 21:27:42 rjkaes Exp $ +/* $Id: conns.c,v 1.22 2004-04-27 18:53:14 rjkaes Exp $ * * Create and free the connection structure. One day there could be * other connection related tasks put here, but for now the header @@ -27,7 +27,8 @@ #include "stats.h" struct conn_s * -initialize_conn(int client_fd, const char* ipaddr, const char* string_addr) +initialize_conn(int client_fd, const char* ipaddr, const char* string_addr, + const char* sock_ipaddr) { struct conn_s *connptr; struct buffer_s *cbuffer, *sbuffer; @@ -71,6 +72,7 @@ initialize_conn(int client_fd, const char* ipaddr, const char* string_addr) /* There is _no_ content length initially */ connptr->content_length.server = connptr->content_length.client = -1; + connptr->server_ip_addr = sock_ipaddr ? safestrdup(sock_ipaddr) : 0; connptr->client_ip_addr = safestrdup(ipaddr); connptr->client_string_addr = safestrdup(string_addr); @@ -122,6 +124,8 @@ destroy_conn(struct conn_s *connptr) if (connptr->error_string) safefree(connptr->error_string); + if (connptr->server_ip_addr) + safefree(connptr->server_ip_addr); if (connptr->client_ip_addr) safefree(connptr->client_ip_addr); if (connptr->client_string_addr) diff --git a/src/conns.h b/src/conns.h index 5d0422a..8b6f69e 100644 --- a/src/conns.h +++ b/src/conns.h @@ -1,4 +1,4 @@ -/* $Id: conns.h,v 1.16 2004-01-26 19:11:51 rjkaes Exp $ +/* $Id: conns.h,v 1.17 2004-04-27 18:53:14 rjkaes Exp $ * * See 'conns.c' for a detailed description. * @@ -53,6 +53,11 @@ struct conn_s { long int client; } content_length; + /* + * Store the server's IP (for BindSame) + */ + char* server_ip_addr; + /* * Store the client's IP and hostname information */ @@ -79,7 +84,8 @@ struct conn_s { * Functions for the creation and destruction of a connection structure. */ extern struct conn_s* initialize_conn(int client_fd, const char* ipaddr, - const char* string_addr); + const char* string_addr, + const char* sock_ipaddr); extern void destroy_conn(struct conn_s *connptr); #endif diff --git a/src/grammar.y b/src/grammar.y index 9f3a74c..72d51b8 100644 --- a/src/grammar.y +++ b/src/grammar.y @@ -1,4 +1,4 @@ -/* $Id: grammar.y,v 1.24 2004-01-26 19:11:51 rjkaes Exp $ +/* $Id: grammar.y,v 1.25 2004-04-27 18:53:14 rjkaes Exp $ * * This is the grammar for tinyproxy's configuration file. It needs to be * in sync with scanner.l. If you know more about yacc and lex than I do @@ -51,7 +51,7 @@ int yylex(void); %token KW_FILTER_CASESENSITIVE %token KW_UPSTREAM %token KW_REVERSEPATH KW_REVERSEONLY KW_REVERSEMAGIC KW_REVERSEBASEURL -%token KW_CONNECTPORT KW_BIND +%token KW_CONNECTPORT KW_BIND KW_BINDSAME %token KW_STATHOST %token KW_ALLOW KW_DENY %token KW_ERRORPAGE KW_DEFAULT_ERRORPAGE @@ -250,6 +250,11 @@ statement log_message(LOG_WARNING, "The 'Bind' directive can not be used with transparent proxy support. Ignoring the directive."); #endif } + | KW_BINDSAME yesno + { + log_message(LOG_INFO, "Binding outgoing connections to incoming IP"); + config.bindsame = $2; + } | KW_VIA_PROXY_NAME string { log_message(LOG_INFO, "Setting \"Via\" proxy name to: %s", $2); diff --git a/src/reqs.c b/src/reqs.c index e03d6c4..d577867 100644 --- a/src/reqs.c +++ b/src/reqs.c @@ -1,4 +1,4 @@ -/* $Id: reqs.c,v 1.111 2004-02-13 21:27:42 rjkaes Exp $ +/* $Id: reqs.c,v 1.112 2004-04-27 18:53:14 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 @@ -645,7 +645,8 @@ process_request(struct conn_s *connptr, hashmap_t hashofheaders) free_request_struct(request); return NULL; - } + } else if (ret == 2) + request->protocol[0] = 0; /* * FIXME: We need to add code for the simple HTTP/0.9 style GET @@ -1111,7 +1112,7 @@ remove_connection_headers(hashmap_t hashofheaders) /* Advance ptr to the next token */ ptr += strlen(ptr) + 1; - while (*ptr == '\0') + while (ptr < data + len && *ptr == '\0') ptr++; } @@ -1609,7 +1610,7 @@ connect_to_upstream(struct conn_s *connptr, struct request_s *request) } connptr->server_fd = - opensock(cur_upstream->host, cur_upstream->port); + opensock(cur_upstream->host, cur_upstream->port, connptr->server_ip_addr); if (connptr->server_fd < 0) { log_message(LOG_WARNING, @@ -1674,15 +1675,22 @@ handle_connection(int fd) struct request_s *request = NULL; hashmap_t hashofheaders = NULL; - char peer_ipaddr[PEER_IP_LENGTH]; - char peer_string[PEER_STRING_LENGTH]; + char sock_ipaddr[IP_LENGTH]; + char peer_ipaddr[IP_LENGTH]; + char peer_string[HOSTNAME_LENGTH]; getpeer_information(fd, peer_ipaddr, peer_string); - log_message(LOG_CONN, "Connect (file descriptor %d): %s [%s]", - fd, peer_string, peer_ipaddr); + if (config.bindsame) + getsock_ip(fd, sock_ipaddr); + + log_message(LOG_CONN, config.bindsame ? + "Connect (file descriptor %d): %s [%s] at [%s]" : + "Connect (file descriptor %d): %s [%s]", + fd, peer_string, peer_ipaddr, sock_ipaddr); - connptr = initialize_conn(fd, peer_ipaddr, peer_string); + connptr = initialize_conn(fd, peer_ipaddr, peer_string, + config.bindsame ? sock_ipaddr : 0); if (!connptr) { close(fd); return; @@ -1748,7 +1756,8 @@ handle_connection(int fd) goto send_error; } } else { - connptr->server_fd = opensock(request->host, request->port); + connptr->server_fd = opensock(request->host, request->port, + connptr->server_ip_addr); if (connptr->server_fd < 0) { indicate_http_error(connptr, 500, "Unable to connect", "detail", PACKAGE " was unable to connect to the remote web server.", diff --git a/src/scanner.l b/src/scanner.l index 8418ca0..3107b31 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -1,4 +1,4 @@ -/* $Id: scanner.l,v 1.23 2004-01-26 19:11:51 rjkaes Exp $ +/* $Id: scanner.l,v 1.24 2004-04-27 18:53:14 rjkaes Exp $ * * This builds the scanner for the tinyproxy configuration file. This * file needs to stay in sync with grammar.y. If someone knows lex and yacc @@ -58,6 +58,7 @@ static struct keyword keywords[] = { { "deny", KW_DENY }, { "connectport", KW_CONNECTPORT }, { "bind", KW_BIND }, + { "bindsame", KW_BINDSAME }, { "viaproxyname", KW_VIA_PROXY_NAME }, { "stathost", KW_STATHOST }, { "errorfile", KW_ERRORPAGE }, diff --git a/src/sock.c b/src/sock.c index 7380b23..265c03d 100644 --- a/src/sock.c +++ b/src/sock.c @@ -1,4 +1,4 @@ -/* $Id: sock.c,v 1.40 2004-02-18 20:18:53 rjkaes Exp $ +/* $Id: sock.c,v 1.41 2004-04-27 18:53:14 rjkaes Exp $ * * Sockets are created and destroyed here. When a new connection comes in from * a client, we need to copy the socket and the create a second socket to the @@ -71,7 +71,7 @@ bind_socket(int sockfd, const char* addr) * independent implementation (mostly for IPv4 and IPv6 addresses.) */ int -opensock(const char* host, int port) +opensock(const char* host, int port, const char* bind_to) { int sockfd, n; struct addrinfo hints, *res, *ressave; @@ -100,7 +100,12 @@ opensock(const char* host, int port) continue; /* ignore this one */ /* Bind to the specified address */ - if (config.bind_address) { + if (bind_to) { + if (bind_socket(sockfd, bind_to) < 0) { + close(sockfd); + continue; /* can't bind, so try again */ + } + } else if (config.bind_address) { if (bind_socket(sockfd, config.bind_address) < 0) { close(sockfd); continue; /* can't bind, so try again */ @@ -198,14 +203,37 @@ listen_sock(uint16_t port, socklen_t* addrlen) return listenfd; } +/* + * Takes a socket descriptor and returns the socket's IP address. + */ +int +getsock_ip(int fd, char* ipaddr) +{ + struct sockaddr_storage name; + int namelen = sizeof(name); + + assert(fd >= 0); + + if (getsockname(fd, (struct sockaddr *) &name, &namelen) != 0) { + log_message(LOG_ERR, "getsock_ip: getsockname() error: %s", + strerror(errno)); + return -1; + } + + if (get_ip_string((struct sockaddr *)&name, ipaddr, IP_LENGTH) == NULL) + return -1; + + return 0; +} + /* * Return the peer's socket information. */ int getpeer_information(int fd, char* ipaddr, char* string_addr) { - struct sockaddr sa; - size_t salen = sizeof(struct sockaddr); + struct sockaddr_storage sa; + size_t salen = sizeof(sa); assert(fd >= 0); assert(ipaddr != NULL); @@ -213,17 +241,17 @@ getpeer_information(int fd, char* ipaddr, char* string_addr) /* Set the strings to default values */ ipaddr[0] = '\0'; - strlcpy(string_addr, "[unknown]", PEER_STRING_LENGTH); + strlcpy(string_addr, "[unknown]", HOSTNAME_LENGTH); /* Look up the IP address */ - if (getpeername(fd, &sa, &salen) != 0) + if (getpeername(fd, (struct sockaddr *)&sa, &salen) != 0) return -1; - if (get_ip_string(&sa, ipaddr, PEER_IP_LENGTH) == NULL) + if (get_ip_string((struct sockaddr *)&sa, ipaddr, IP_LENGTH) == NULL) return -1; /* Get the full host name */ - return getnameinfo(&sa, salen, - string_addr, PEER_STRING_LENGTH, + return getnameinfo((struct sockaddr *)&sa, salen, + string_addr, HOSTNAME_LENGTH, NULL, 0, 0); } diff --git a/src/sock.h b/src/sock.h index 78191ea..b0c1a96 100644 --- a/src/sock.h +++ b/src/sock.h @@ -1,4 +1,4 @@ -/* $Id: sock.h,v 1.12 2004-02-18 20:18:53 rjkaes Exp $ +/* $Id: sock.h,v 1.13 2004-04-27 18:53:14 rjkaes Exp $ * * See 'sock.c' for a detailed description. * @@ -20,17 +20,18 @@ #define TINYPROXY_SOCK_H /* The IP length is set to 48, since IPv6 can be that long */ -#define PEER_IP_LENGTH 48 -#define PEER_STRING_LENGTH 1024 +#define IP_LENGTH 48 +#define HOSTNAME_LENGTH 1024 #define MAXLINE (1024 * 4) -extern int opensock(const char* host, int port); +extern int opensock(const char* host, int port, const char* bind_to); extern int listen_sock(uint16_t port, socklen_t* addrlen); extern int socket_nonblocking(int sock); extern int socket_blocking(int sock); +extern int getsock_ip(int fd, char* ipaddr); extern int getpeer_information(int fd, char* ipaddr, char* string_addr); #endif diff --git a/src/tinyproxy.h b/src/tinyproxy.h index ad02120..256b9e7 100644 --- a/src/tinyproxy.h +++ b/src/tinyproxy.h @@ -1,4 +1,4 @@ -/* $Id: tinyproxy.h,v 1.43 2004-01-26 19:11:51 rjkaes Exp $ +/* $Id: tinyproxy.h,v 1.44 2004-04-27 18:53:14 rjkaes Exp $ * * See 'tinyproxy.c' for a detailed description. * @@ -80,6 +80,7 @@ struct config_s { char *pidpath; unsigned int idletimeout; char* bind_address; + unsigned int bindsame; /* * The configured name to use in the HTTP "Via" header field. -- cgit v1.2.3