Improved the upstream proxy support by making the upstream proxy

server configurable based on the destination host.  [Code written by
Peter da Silva]
This commit is contained in:
Robert James Kaes 2003-05-29 19:44:00 +00:00
parent 2e9f27769d
commit 4a377a712d
5 changed files with 210 additions and 23 deletions

View File

@ -92,6 +92,32 @@ PidFile "/var/run/tinyproxy.pid"
#
# Turns on upstream proxy support.
#
# The upstream rules allow you to selectively route upstream connections
# based on the host/domain of the site being accessed.
#
# For example:
# # connection to test domain goes through testproxy
# upstream testproxy:8008 .test.domain.invalid
# upstream testproxy:8008 .our_testbed.example.com
#
# # no upstream proxy for internal websites and unqualified hosts
# no upstream .internal.example.com
# no upstream www.example.com
# no upstream .
#
# # connection to these boxes go through their DMZ firewalls
# upstream cust1_firewall:8008 testbed_for_cust1
# upstream cust2_firewall:8008 testbed_for_cust2
#
# # default upstream is internet firewall
# upstream firewall.internal.example.com:80
#
# The LAST matching rule wins the route decision. As you can see, you
# can use a host, or a domain:
# name matches host exactly
# .name matches any host in domain "name"
# . matches any host with no domain (in 'empty' domain)
#
#Upstream some.remote.proxy:port
#

View File

@ -1,4 +1,4 @@
/* $Id: grammar.y,v 1.20 2003-03-13 21:42:46 rjkaes Exp $
/* $Id: grammar.y,v 1.21 2003-05-29 19:43:58 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
@ -171,12 +171,27 @@ statement
| KW_UPSTREAM unique_address ':' NUMBER
{
#ifdef UPSTREAM_SUPPORT
config.upstream_name = $2;
config.upstream_port = $4;
upstream_add($2, $4, NULL);
#else
log_message(LOG_WARNING, "Upstream proxy support was not compiled in.");
#endif
}
| KW_UPSTREAM unique_address ':' NUMBER STRING
{
#ifdef UPSTREAM_SUPPORT
upstream_add($2, $4, $5);
#else
log_message(LOG_WARNING, "Upstream proxy support was not compiled in.");
#endif
}
| KW_NO KW_UPSTREAM STRING
{
#ifdef UPSTREAM_SUPPORT
upstream_add(NULL, 0, $3);
#else
log_message(LOG_WARNING, "Upstream proxy support was not compiled in.");
#endif
}
| KW_LISTEN NUMERIC_ADDRESS
{
log_message(LOG_INFO, "Establishing listening socket on IP %s", $2);

View File

@ -1,4 +1,4 @@
/* $Id: reqs.c,v 1.97 2003-05-05 16:46:05 rjkaes Exp $
/* $Id: reqs.c,v 1.98 2003-05-29 19:43:57 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
@ -57,9 +57,11 @@
* enabled.
*/
#ifdef UPSTREAM_SUPPORT
# define UPSTREAM_CONFIGURED() (config.upstream_name && config.upstream_port != -1)
# define UPSTREAM_CONFIGURED() (config.upstream_list != NULL)
# define UPSTREAM_HOST(host) upstream_get(host)
#else
# define UPSTREAM_CONFIGURED() (0)
# define UPSTREAM_HOST(host) (NULL)
#endif
/*
@ -73,6 +75,19 @@
*/
static vector_t ports_allowed_by_connect = NULL;
/*
* This structure holds the information pulled from a URL request.
*/
struct request_s {
char *method;
char *protocol;
char *host;
uint16_t port;
char *path;
};
/*
* Now, this routine adds a "port" to the list. It also creates the list if
* it hasn't already by done.
@ -163,18 +178,8 @@ read_request_line(struct conn_s *connptr)
}
/*
* This structure holds the information pulled from a URL request.
* Free all the memory allocated in a request.
*/
struct request_s {
char *method;
char *protocol;
char *host;
uint16_t port;
char *path;
};
static void
free_request_struct(struct request_s *request)
{
@ -304,6 +309,129 @@ build_url(char **url, const char *host, int port, const char *path)
}
#endif /* TRANSPARENT_PROXY */
#ifdef UPSTREAM_SUPPORT
/*
* Add an entry to the upstream list
*/
void
upstream_add(const char *host, int port, const char *domain)
{
struct upstream *up = safemalloc(sizeof (struct upstream));
if (!up) {
log_message(LOG_WARNING,
"Could not allocate memory for upstream host configuration");
return;
}
if (domain && domain[0] != '\0')
up->domain = safestrdup(domain);
else
up->domain = NULL;
if (host && host[0] != '\0' && port > 0)
up->host = safestrdup(host);
else
up->host = NULL;
if (port > 0)
up->port = port;
else
up->port = 0;
if (host) {
log_message(LOG_INFO, "Adding upstream %s:%d for %s",
host, port, domain ? domain : "[default]");
} else if (domain) {
log_message(LOG_INFO, "Adding no-upstream for %s",
domain ? domain : "[default]");
} else {
log_message(LOG_WARNING,
"Nonsense upstream rule: no proxy or domain");
goto upstream_cleanup;
}
if (!up->domain) {
/* always add default to end */
struct upstream *tmp = config.upstream_list;
while (tmp) {
if (!tmp->domain) {
log_message(LOG_WARNING,
"Duplicate default upstream");
goto upstream_cleanup;
}
if (!tmp->next) {
up->next = NULL;
tmp->next = up;
return;
}
tmp = tmp->next;
}
}
up->next = config.upstream_list;
config.upstream_list = up;
return;
upstream_cleanup:
safefree(up->host);
safefree(up->domain);
safefree(up);
return;
}
/*
* Check if a host is in the upstream list
*/
static struct upstream *
upstream_get(char *host)
{
struct upstream *up = config.upstream_list;
while (up) {
if (!up->domain)
break; /* no domain, default, match */
if (strcasecmp(host, up->domain) == 0)
break; /* exact match */
if (up->domain[0] == '.') { /* domain starts with dot... */
char *dot = strchr(host, '.');
if (!dot && !up->domain[1])
break; /* domain exactly ".", host is local */
while (dot) {
if (strcasecmp(dot, up->domain) == 0)
break; /* subdomain match */
dot = strchr(dot+1, '.');
}
if (dot)
break; /* trailing part of domain matches */
}
up = up->next;
}
if (up && (!up->host || !up->port))
up = NULL;
if (up)
log_message(LOG_INFO, "Found proxy %s:%d for %s",
up->host, up->port, host);
else
log_message(LOG_INFO, "No proxy for %s", host);
return up;
}
#endif
/*
* Create a connection for HTTP connections.
*/
@ -1249,8 +1377,17 @@ connect_to_upstream(struct conn_s *connptr, struct request_s *request)
char *combined_string;
int len;
struct upstream *cur_upstream = upstream_get(request->host);
if(!cur_upstream) {
log_message(LOG_WARNING,
"No upstream proxy defined for %s.",
request->host);
indicate_http_error(connptr, 404, "Unable to connect to upstream proxy.");
return -1;
}
connptr->server_fd =
opensock(config.upstream_name, config.upstream_port);
opensock(cur_upstream->host, cur_upstream->port);
if (connptr->server_fd < 0) {
log_message(LOG_WARNING,
@ -1263,7 +1400,7 @@ connect_to_upstream(struct conn_s *connptr, struct request_s *request)
log_message(LOG_CONN,
"Established connection to upstream proxy \"%s\" using file descriptor %d.",
config.upstream_name, connptr->server_fd);
cur_upstream->host, connptr->server_fd);
/*
* We need to re-write the "path" part of the request so that we
@ -1383,7 +1520,7 @@ handle_connection(int fd)
goto send_error;
}
if (UPSTREAM_CONFIGURED()) {
if (UPSTREAM_CONFIGURED() && (UPSTREAM_HOST(request->host) != NULL)) {
if (connect_to_upstream(connptr, request) < 0) {
goto send_error;
}

View File

@ -1,4 +1,4 @@
/* $Id: reqs.h,v 1.3 2002-04-12 17:00:42 rjkaes Exp $
/* $Id: reqs.h,v 1.4 2003-05-29 19:43:57 rjkaes Exp $
*
* See 'reqs.c' for a detailed description.
*
@ -21,5 +21,6 @@
extern void handle_connection(int fd);
extern void add_connect_port_allowed(int port);
extern void upstream_add(const char *host, int port, const char *domain);
#endif

View File

@ -1,4 +1,4 @@
/* $Id: tinyproxy.h,v 1.38 2003-03-13 21:32:33 rjkaes Exp $
/* $Id: tinyproxy.h,v 1.39 2003-05-29 19:43:57 rjkaes Exp $
*
* See 'tinyproxy.c' for a detailed description.
*
@ -25,6 +25,15 @@
#define MAXBUFFSIZE ((size_t)(1024 * 96)) /* Max size of buffer */
#define MAX_IDLE_TIME (60 * 10) /* 10 minutes of no activity */
#ifdef UPSTREAM_SUPPORT
struct upstream {
struct upstream *next;
char *domain; /* optional */
char *host;
int port;
};
#endif
struct config_s {
char *logf_name;
char *config_file;
@ -45,8 +54,7 @@ struct config_s {
char *my_domain;
#endif
#ifdef UPSTREAM_SUPPORT
char *upstream_name;
int upstream_port;
struct upstream *upstream_list;
#endif /* UPSTREAM_SUPPORT */
char *pidpath;
unsigned int idletimeout;