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:
parent
2e9f27769d
commit
4a377a712d
@ -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
|
||||
|
||||
#
|
||||
|
@ -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);
|
||||
|
169
src/reqs.c
169
src/reqs.c
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user