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.
master
Robert James Kaes 2004-04-27 18:53:14 +00:00
parent 3b961ec66b
commit 18df4910a4
9 changed files with 93 additions and 32 deletions

View File

@ -33,6 +33,12 @@ Port 8888
#
#Bind 192.168.0.1
#
# BindSame: If enabled, tinyproxy will bind the outgoing connection to the
# ip address of the incomming connection.
#
#BindSame yes
#
# Timeout: The maximum number of seconds of inactivity a connection is
# allowed to have before it is closed by tinyproxy.

View File

@ -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)

View File

@ -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

View File

@ -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);

View File

@ -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);
connptr = initialize_conn(fd, peer_ipaddr, peer_string);
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,
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.",

View File

@ -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 },

View File

@ -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);
}

View File

@ -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

View File

@ -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.