Add regex option for upstream proxy selection
This commit is contained in:
parent
69c86b987b
commit
93e9c156e8
10
configure.ac
10
configure.ac
@ -64,6 +64,16 @@ if test x"$filter_enabled" = x"yes"; then
|
||||
AC_DEFINE(FILTER_ENABLE)
|
||||
fi
|
||||
|
||||
dnl Include support for regex in upstream proxies?
|
||||
AH_TEMPLATE([UPSTREAM_REGEX],
|
||||
[Include support for connecting to an upstream proxy based on a regex.])
|
||||
TP_ARG_ENABLE(upstream_regex,
|
||||
[Enable upstream proxying (default is YES)],
|
||||
yes)
|
||||
if test x"$upstream_regex_enabled" = x"yes"; then
|
||||
AC_DEFINE(UPSTREAM_REGEX)
|
||||
fi
|
||||
|
||||
dnl Include support for upstream proxies?
|
||||
AH_TEMPLATE([UPSTREAM_SUPPORT],
|
||||
[Include support for connecting to an upstream proxy.])
|
||||
|
349
src/reqs.c
349
src/reqs.c
@ -60,13 +60,13 @@
|
||||
* enabled.
|
||||
*/
|
||||
#ifdef UPSTREAM_SUPPORT
|
||||
# define UPSTREAM_CONFIGURED() (config.upstream_list != NULL)
|
||||
# define UPSTREAM_HOST(host) upstream_get(host, config.upstream_list)
|
||||
# define UPSTREAM_IS_HTTP(conn) (conn->upstream_proxy != NULL && conn->upstream_proxy->type == PT_HTTP)
|
||||
#define UPSTREAM_CONFIGURED() (config.upstream_list != NULL)
|
||||
#define UPSTREAM_REQUEST(request) upstream_get(request, config.upstream_list)
|
||||
#define UPSTREAM_IS_HTTP(conn) (conn->upstream_proxy != NULL && conn->upstream_proxy->type == PT_HTTP)
|
||||
#else
|
||||
# define UPSTREAM_CONFIGURED() (0)
|
||||
# define UPSTREAM_HOST(host) (NULL)
|
||||
# define UPSTREAM_IS_HTTP(up) (0)
|
||||
#define UPSTREAM_CONFIGURED() (0)
|
||||
#define UPSTREAM_REQUEST(request) (request->host)
|
||||
#define UPSTREAM_IS_HTTP(up) (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -130,6 +130,7 @@ static void free_request_struct (struct request_s *request)
|
||||
|
||||
safefree (request->method);
|
||||
safefree (request->protocol);
|
||||
safefree (request->url);
|
||||
|
||||
if (request->host)
|
||||
safefree (request->host);
|
||||
@ -195,23 +196,25 @@ static int strip_return_port (char *host)
|
||||
* (proxied) ftp:// urls and https-requests that
|
||||
* come in without the proto:// part via CONNECT.
|
||||
*/
|
||||
static int extract_url (const char *url, int default_port,
|
||||
static int extract_url (const char *lurl, const char *surl, int default_port,
|
||||
struct request_s *request)
|
||||
{
|
||||
char *p;
|
||||
int port;
|
||||
|
||||
/* Split the URL on the slash to separate host from path */
|
||||
p = strchr (url, '/');
|
||||
|
||||
request->url = safestrdup (lurl);
|
||||
p = strchr (surl, '/');
|
||||
if (p != NULL) {
|
||||
int len;
|
||||
len = p - url;
|
||||
len = p - surl;
|
||||
request->host = (char *) safemalloc (len + 1);
|
||||
memcpy (request->host, url, len);
|
||||
memcpy (request->host, surl, len);
|
||||
request->host[len] = '\0';
|
||||
request->path = safestrdup (p);
|
||||
} else {
|
||||
request->host = safestrdup (url);
|
||||
request->host = safestrdup (surl);
|
||||
request->path = safestrdup ("/");
|
||||
}
|
||||
|
||||
@ -228,8 +231,8 @@ static int extract_url (const char *url, int default_port,
|
||||
/* Remove any surrounding '[' and ']' from IPv6 literals */
|
||||
p = strrchr (request->host, ']');
|
||||
if (p && (*(request->host) == '[')) {
|
||||
memmove(request->host, request->host + 1,
|
||||
strlen(request->host) - 2);
|
||||
memmove (request->host, request->host + 1,
|
||||
strlen (request->host) - 2);
|
||||
*p = '\0';
|
||||
p--;
|
||||
*p = '\0';
|
||||
@ -238,6 +241,7 @@ static int extract_url (const char *url, int default_port,
|
||||
return 0;
|
||||
|
||||
ERROR_EXIT:
|
||||
safefree (request->url);
|
||||
if (request->host)
|
||||
safefree (request->host);
|
||||
if (request->path)
|
||||
@ -253,7 +257,7 @@ static int
|
||||
establish_http_connection (struct conn_s *connptr, struct request_s *request)
|
||||
{
|
||||
char portbuff[7];
|
||||
char dst[sizeof(struct in6_addr)];
|
||||
char dst[sizeof (struct in6_addr)];
|
||||
|
||||
/* Build a port string if it's not a standard port */
|
||||
if (request->port != HTTP_PORT && request->port != HTTP_PORT_SSL)
|
||||
@ -261,7 +265,7 @@ establish_http_connection (struct conn_s *connptr, struct request_s *request)
|
||||
else
|
||||
portbuff[0] = '\0';
|
||||
|
||||
if (inet_pton(AF_INET6, request->host, dst) > 0) {
|
||||
if (inet_pton (AF_INET6, request->host, dst) > 0) {
|
||||
/* host is an IPv6 address literal, so surround it with
|
||||
* [] */
|
||||
return write_message (connptr->server_fd,
|
||||
@ -403,14 +407,14 @@ BAD_REQUEST_ERROR:
|
||||
{
|
||||
char *skipped_type = strstr (url, "//") + 2;
|
||||
|
||||
if (extract_url (skipped_type, HTTP_PORT, request) < 0) {
|
||||
if (extract_url (url, skipped_type, HTTP_PORT, request) < 0) {
|
||||
indicate_http_error (connptr, 400, "Bad Request",
|
||||
"detail", "Could not parse URL",
|
||||
"url", url, NULL);
|
||||
goto fail;
|
||||
}
|
||||
} else if (strcmp (request->method, "CONNECT") == 0) {
|
||||
if (extract_url (url, HTTP_PORT_SSL, request) < 0) {
|
||||
if (extract_url (url, url, HTTP_PORT_SSL, request) < 0) {
|
||||
indicate_http_error (connptr, 400, "Bad Request",
|
||||
"detail", "Could not parse URL",
|
||||
"url", url, NULL);
|
||||
@ -419,8 +423,7 @@ BAD_REQUEST_ERROR:
|
||||
|
||||
/* Verify that the port in the CONNECT method is allowed */
|
||||
if (!check_allowed_connect_ports (request->port,
|
||||
config.connect_ports))
|
||||
{
|
||||
config.connect_ports)) {
|
||||
indicate_http_error (connptr, 403, "Access violation",
|
||||
"detail",
|
||||
"The CONNECT method not allowed "
|
||||
@ -481,7 +484,6 @@ BAD_REQUEST_ERROR:
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Check to see if they're requesting the stat host
|
||||
*/
|
||||
@ -539,8 +541,8 @@ static int pull_client_data (struct conn_s *connptr, long int length)
|
||||
*/
|
||||
ret = socket_nonblocking (connptr->client_fd);
|
||||
if (ret != 0) {
|
||||
log_message(LOG_ERR, "Failed to set the client socket "
|
||||
"to non-blocking: %s", strerror(errno));
|
||||
log_message (LOG_ERR, "Failed to set the client socket "
|
||||
"to non-blocking: %s", strerror (errno));
|
||||
goto ERROR_EXIT;
|
||||
}
|
||||
|
||||
@ -548,8 +550,8 @@ static int pull_client_data (struct conn_s *connptr, long int length)
|
||||
|
||||
ret = socket_blocking (connptr->client_fd);
|
||||
if (ret != 0) {
|
||||
log_message(LOG_ERR, "Failed to set the client socket "
|
||||
"to blocking: %s", strerror(errno));
|
||||
log_message (LOG_ERR, "Failed to set the client socket "
|
||||
"to blocking: %s", strerror (errno));
|
||||
goto ERROR_EXIT;
|
||||
}
|
||||
|
||||
@ -562,8 +564,8 @@ static int pull_client_data (struct conn_s *connptr, long int length)
|
||||
bytes_read = read (connptr->client_fd, buffer, 2);
|
||||
if (bytes_read == -1) {
|
||||
log_message
|
||||
(LOG_WARNING,
|
||||
"Could not read two bytes from POST message");
|
||||
(LOG_WARNING,
|
||||
"Could not read two bytes from POST message");
|
||||
}
|
||||
}
|
||||
|
||||
@ -870,7 +872,7 @@ process_client_headers (struct conn_s *connptr, hashmap_t hashofheaders)
|
||||
* http proxy is in use.)
|
||||
*/
|
||||
if (connptr->server_fd == -1 || connptr->show_stats
|
||||
|| (connptr->connect_method && ! UPSTREAM_IS_HTTP(connptr))) {
|
||||
|| (connptr->connect_method && !UPSTREAM_IS_HTTP (connptr))) {
|
||||
log_message (LOG_INFO,
|
||||
"Not sending client headers to remote machine");
|
||||
return 0;
|
||||
@ -1089,8 +1091,8 @@ retry:
|
||||
while (reverse) {
|
||||
if (strncasecmp (header,
|
||||
reverse->url, (len =
|
||||
strlen (reverse->
|
||||
url))) == 0)
|
||||
strlen (reverse->url)))
|
||||
== 0)
|
||||
break;
|
||||
reverse = reverse->next;
|
||||
}
|
||||
@ -1161,15 +1163,15 @@ static void relay_connection (struct conn_s *connptr)
|
||||
|
||||
ret = socket_nonblocking (connptr->client_fd);
|
||||
if (ret != 0) {
|
||||
log_message(LOG_ERR, "Failed to set the client socket "
|
||||
"to non-blocking: %s", strerror(errno));
|
||||
log_message (LOG_ERR, "Failed to set the client socket "
|
||||
"to non-blocking: %s", strerror (errno));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = socket_nonblocking (connptr->server_fd);
|
||||
if (ret != 0) {
|
||||
log_message(LOG_ERR, "Failed to set the server socket "
|
||||
"to non-blocking: %s", strerror(errno));
|
||||
log_message (LOG_ERR, "Failed to set the server socket "
|
||||
"to non-blocking: %s", strerror (errno));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1248,9 +1250,9 @@ static void relay_connection (struct conn_s *connptr)
|
||||
*/
|
||||
ret = socket_blocking (connptr->client_fd);
|
||||
if (ret != 0) {
|
||||
log_message(LOG_ERR,
|
||||
"Failed to set client socket to blocking: %s",
|
||||
strerror(errno));
|
||||
log_message (LOG_ERR,
|
||||
"Failed to set client socket to blocking: %s",
|
||||
strerror (errno));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1265,9 +1267,9 @@ static void relay_connection (struct conn_s *connptr)
|
||||
*/
|
||||
ret = socket_blocking (connptr->server_fd);
|
||||
if (ret != 0) {
|
||||
log_message(LOG_ERR,
|
||||
"Failed to set server socket to blocking: %s",
|
||||
strerror(errno));
|
||||
log_message (LOG_ERR,
|
||||
"Failed to set server socket to blocking: %s",
|
||||
strerror (errno));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1280,121 +1282,128 @@ static void relay_connection (struct conn_s *connptr)
|
||||
}
|
||||
|
||||
static int
|
||||
connect_to_upstream_proxy(struct conn_s *connptr, struct request_s *request)
|
||||
connect_to_upstream_proxy (struct conn_s *connptr, struct request_s *request)
|
||||
{
|
||||
unsigned len;
|
||||
unsigned char buff[512]; /* won't use more than 7 + 255 */
|
||||
unsigned short port;
|
||||
size_t ulen, passlen;
|
||||
unsigned len;
|
||||
unsigned char buff[512]; /* won't use more than 7 + 255 */
|
||||
unsigned short port;
|
||||
size_t ulen, passlen;
|
||||
|
||||
struct hostent *host;
|
||||
struct upstream *cur_upstream = connptr->upstream_proxy;
|
||||
struct hostent *host;
|
||||
struct upstream *cur_upstream = connptr->upstream_proxy;
|
||||
|
||||
ulen = cur_upstream->ua.user ? strlen(cur_upstream->ua.user) : 0;
|
||||
passlen = cur_upstream->pass ? strlen(cur_upstream->pass) : 0;
|
||||
ulen = cur_upstream->ua.user ? strlen (cur_upstream->ua.user) : 0;
|
||||
passlen = cur_upstream->pass ? strlen (cur_upstream->pass) : 0;
|
||||
|
||||
log_message (LOG_CONN,
|
||||
"Established connection to %s proxy \"%s\" using file descriptor %d.",
|
||||
proxy_type_name (cur_upstream->type), cur_upstream->host,
|
||||
connptr->server_fd);
|
||||
|
||||
log_message(LOG_CONN,
|
||||
"Established connection to %s proxy \"%s\" using file descriptor %d.",
|
||||
proxy_type_name(cur_upstream->type), cur_upstream->host, connptr->server_fd);
|
||||
if (cur_upstream->type == PT_SOCKS4) {
|
||||
|
||||
if (cur_upstream->type == PT_SOCKS4) {
|
||||
buff[0] = 4; /* socks version */
|
||||
buff[1] = 1; /* connect command */
|
||||
port = htons (request->port);
|
||||
memcpy (&buff[2], &port, 2); /* dest port */
|
||||
host = gethostbyname (request->host);
|
||||
memcpy (&buff[4], host->h_addr_list[0], 4); /* dest ip */
|
||||
buff[8] = 0; /* user */
|
||||
if (9 != safe_write (connptr->server_fd, buff, 9))
|
||||
return -1;
|
||||
if (8 != safe_read (connptr->server_fd, buff, 8))
|
||||
return -1;
|
||||
if (buff[0] != 0 || buff[1] != 90)
|
||||
return -1;
|
||||
|
||||
buff[0] = 4; /* socks version */
|
||||
buff[1] = 1; /* connect command */
|
||||
port = htons(request->port);
|
||||
memcpy(&buff[2], &port, 2); /* dest port */
|
||||
host = gethostbyname(request->host);
|
||||
memcpy(&buff[4], host->h_addr_list[0], 4); /* dest ip */
|
||||
buff[8] = 0; /* user */
|
||||
if (9 != safe_write(connptr->server_fd, buff, 9))
|
||||
return -1;
|
||||
if (8 != safe_read(connptr->server_fd, buff, 8))
|
||||
return -1;
|
||||
if (buff[0]!=0 || buff[1]!=90)
|
||||
return -1;
|
||||
} else if (cur_upstream->type == PT_SOCKS5) {
|
||||
|
||||
} else if (cur_upstream->type == PT_SOCKS5) {
|
||||
/* init */
|
||||
int n_methods = ulen ? 2 : 1;
|
||||
buff[0] = 5; /* socks version */
|
||||
buff[1] = n_methods; /* number of methods */
|
||||
buff[2] = 0; /* no auth method */
|
||||
if (ulen)
|
||||
buff[3] = 2; /* auth method -> username / password */
|
||||
if (2 + n_methods !=
|
||||
safe_write (connptr->server_fd, buff, 2 + n_methods))
|
||||
return -1;
|
||||
if (2 != safe_read (connptr->server_fd, buff, 2))
|
||||
return -1;
|
||||
if (buff[0] != 5 || (buff[1] != 0 && buff[1] != 2))
|
||||
return -1;
|
||||
|
||||
/* init */
|
||||
int n_methods = ulen ? 2 : 1;
|
||||
buff[0] = 5; /* socks version */
|
||||
buff[1] = n_methods; /* number of methods */
|
||||
buff[2] = 0; /* no auth method */
|
||||
if (ulen) buff[3] = 2; /* auth method -> username / password */
|
||||
if (2+n_methods != safe_write(connptr->server_fd, buff, 2+n_methods))
|
||||
return -1;
|
||||
if (2 != safe_read(connptr->server_fd, buff, 2))
|
||||
return -1;
|
||||
if (buff[0] != 5 || (buff[1] != 0 && buff[1] != 2))
|
||||
return -1;
|
||||
if (buff[1] == 2) {
|
||||
/* authentication */
|
||||
char in[2];
|
||||
char out[515];
|
||||
char *cur = out;
|
||||
size_t c;
|
||||
*cur++ = 1; /* version */
|
||||
c = ulen & 0xFF;
|
||||
*cur++ = c;
|
||||
memcpy (cur, cur_upstream->ua.user, c);
|
||||
cur += c;
|
||||
c = passlen & 0xFF;
|
||||
*cur++ = c;
|
||||
memcpy (cur, cur_upstream->pass, c);
|
||||
cur += c;
|
||||
|
||||
if (buff[1] == 2) {
|
||||
/* authentication */
|
||||
char in[2];
|
||||
char out[515];
|
||||
char *cur = out;
|
||||
size_t c;
|
||||
*cur++ = 1; /* version */
|
||||
c = ulen & 0xFF;
|
||||
*cur++ = c;
|
||||
memcpy(cur, cur_upstream->ua.user, c);
|
||||
cur += c;
|
||||
c = passlen & 0xFF;
|
||||
*cur++ = c;
|
||||
memcpy(cur, cur_upstream->pass, c);
|
||||
cur += c;
|
||||
if ((cur - out) !=
|
||||
safe_write (connptr->server_fd, out, cur - out))
|
||||
return -1;
|
||||
|
||||
if((cur - out) != safe_write(connptr->server_fd, out, cur - out))
|
||||
return -1;
|
||||
if (2 != safe_read (connptr->server_fd, in, 2))
|
||||
return -1;
|
||||
if (in[1] != 0 || !(in[0] == 5 || in[0] == 1)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* connect */
|
||||
buff[0] = 5; /* socks version */
|
||||
buff[1] = 1; /* connect */
|
||||
buff[2] = 0; /* reserved */
|
||||
buff[3] = 3; /* domainname */
|
||||
len = strlen (request->host);
|
||||
if (len > 255)
|
||||
return -1;
|
||||
buff[4] = len; /* length of domainname */
|
||||
memcpy (&buff[5], request->host, len); /* dest ip */
|
||||
port = htons (request->port);
|
||||
memcpy (&buff[5 + len], &port, 2); /* dest port */
|
||||
if (7 + len != safe_write (connptr->server_fd, buff, 7 + len))
|
||||
return -1;
|
||||
if (4 != safe_read (connptr->server_fd, buff, 4))
|
||||
return -1;
|
||||
if (buff[0] != 5 || buff[1] != 0)
|
||||
return -1;
|
||||
switch (buff[3]) {
|
||||
case 1:
|
||||
len = 4;
|
||||
break; /* ip v4 */
|
||||
case 4:
|
||||
len = 16;
|
||||
break; /* ip v6 */
|
||||
case 3: /* domainname */
|
||||
if (1 != safe_read (connptr->server_fd, buff, 1))
|
||||
return -1;
|
||||
len = buff[0]; /* max = 255 */
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
if (2 + len != safe_read (connptr->server_fd, buff, 2 + len))
|
||||
return -1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(2 != safe_read(connptr->server_fd, in, 2))
|
||||
return -1;
|
||||
if(in[1] != 0 || !(in[0] == 5 || in[0] == 1)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* connect */
|
||||
buff[0] = 5; /* socks version */
|
||||
buff[1] = 1; /* connect */
|
||||
buff[2] = 0; /* reserved */
|
||||
buff[3] = 3; /* domainname */
|
||||
len=strlen(request->host);
|
||||
if(len>255)
|
||||
return -1;
|
||||
buff[4] = len; /* length of domainname */
|
||||
memcpy(&buff[5], request->host, len); /* dest ip */
|
||||
port = htons(request->port);
|
||||
memcpy(&buff[5+len], &port, 2); /* dest port */
|
||||
if (7+len != safe_write(connptr->server_fd, buff, 7+len))
|
||||
return -1;
|
||||
if (4 != safe_read(connptr->server_fd, buff, 4))
|
||||
return -1;
|
||||
if (buff[0]!=5 || buff[1]!=0)
|
||||
return -1;
|
||||
switch(buff[3]) {
|
||||
case 1: len=4; break; /* ip v4 */
|
||||
case 4: len=16; break; /* ip v6 */
|
||||
case 3: /* domainname */
|
||||
if (1 != safe_read(connptr->server_fd, buff, 1))
|
||||
return -1;
|
||||
len = buff[0]; /* max = 255 */
|
||||
break;
|
||||
default: return -1;
|
||||
}
|
||||
if (2+len != safe_read(connptr->server_fd, buff, 2+len))
|
||||
return -1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
if (connptr->connect_method)
|
||||
return 0;
|
||||
|
||||
if (connptr->connect_method)
|
||||
return 0;
|
||||
|
||||
return establish_http_connection(connptr, request);
|
||||
return establish_http_connection (connptr, request);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Establish a connection to the upstream proxy server.
|
||||
*/
|
||||
@ -1438,8 +1447,8 @@ connect_to_upstream (struct conn_s *connptr, struct request_s *request)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cur_upstream->type != PT_HTTP)
|
||||
return connect_to_upstream_proxy(connptr, request);
|
||||
if (cur_upstream->type != PT_HTTP)
|
||||
return connect_to_upstream_proxy (connptr, request);
|
||||
|
||||
log_message (LOG_CONN,
|
||||
"Established connection to upstream proxy \"%s\" "
|
||||
@ -1480,8 +1489,7 @@ connect_to_upstream (struct conn_s *connptr, struct request_s *request)
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
get_request_entity(struct conn_s *connptr)
|
||||
static int get_request_entity (struct conn_s *connptr)
|
||||
{
|
||||
int ret;
|
||||
fd_set rset;
|
||||
@ -1496,9 +1504,9 @@ get_request_entity(struct conn_s *connptr)
|
||||
if (ret == -1) {
|
||||
log_message (LOG_ERR,
|
||||
"Error calling select on client fd %d: %s",
|
||||
connptr->client_fd, strerror(errno));
|
||||
connptr->client_fd, strerror (errno));
|
||||
} else if (ret == 0) {
|
||||
log_message (LOG_INFO, "no entity");
|
||||
log_message (LOG_INFO, "no entity");
|
||||
} else if (ret == 1 && FD_ISSET (connptr->client_fd, &rset)) {
|
||||
ssize_t nread;
|
||||
nread = read_buffer (connptr->client_fd, connptr->cbuffer);
|
||||
@ -1509,8 +1517,7 @@ get_request_entity(struct conn_s *connptr)
|
||||
ret = -1;
|
||||
} else {
|
||||
log_message (LOG_INFO,
|
||||
"Read request entity of %d bytes",
|
||||
nread);
|
||||
"Read request entity of %d bytes", nread);
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
@ -1523,7 +1530,6 @@ get_request_entity(struct conn_s *connptr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This is the main drive for each connection. As you can tell, for the
|
||||
* first few steps we are using a blocking socket. If you remember the
|
||||
@ -1612,34 +1618,44 @@ void handle_connection (int fd)
|
||||
ssize_t len;
|
||||
char *authstring;
|
||||
int failure = 1, stathost_connect = 0;
|
||||
len = hashmap_entry_by_key (hashofheaders, "proxy-authorization",
|
||||
(void **) &authstring);
|
||||
len =
|
||||
hashmap_entry_by_key (hashofheaders, "proxy-authorization",
|
||||
(void **) &authstring);
|
||||
|
||||
if (len == 0 && config.stathost) {
|
||||
len = hashmap_entry_by_key (hashofheaders, "host",
|
||||
(void **) &authstring);
|
||||
if (len && !strncmp(authstring, config.stathost, strlen(config.stathost))) {
|
||||
len = hashmap_entry_by_key (hashofheaders, "authorization",
|
||||
(void **) &authstring);
|
||||
if (len
|
||||
&& !strncmp (authstring, config.stathost,
|
||||
strlen (config.stathost))) {
|
||||
len =
|
||||
hashmap_entry_by_key (hashofheaders,
|
||||
"authorization",
|
||||
(void **)
|
||||
&authstring);
|
||||
stathost_connect = 1;
|
||||
} else len = 0;
|
||||
} else
|
||||
len = 0;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
if (stathost_connect) goto e401;
|
||||
if (stathost_connect)
|
||||
goto e401;
|
||||
update_stats (STAT_DENIED);
|
||||
indicate_http_error (connptr, 407, "Proxy Authentication Required",
|
||||
indicate_http_error (connptr, 407,
|
||||
"Proxy Authentication Required",
|
||||
"detail",
|
||||
"This proxy requires authentication.",
|
||||
NULL);
|
||||
goto fail;
|
||||
}
|
||||
if ( /* currently only "basic" auth supported */
|
||||
(strncmp(authstring, "Basic ", 6) == 0 ||
|
||||
strncmp(authstring, "basic ", 6) == 0) &&
|
||||
basicauth_check (config.basicauth_list, authstring + 6) == 1)
|
||||
failure = 0;
|
||||
if(failure) {
|
||||
if ( /* currently only "basic" auth supported */
|
||||
(strncmp (authstring, "Basic ", 6) == 0 ||
|
||||
strncmp (authstring, "basic ", 6) == 0) &&
|
||||
basicauth_check (config.basicauth_list,
|
||||
authstring + 6) == 1)
|
||||
failure = 0;
|
||||
if (failure) {
|
||||
e401:
|
||||
update_stats (STAT_DENIED);
|
||||
indicate_http_error (connptr, 401, "Unauthorized",
|
||||
@ -1658,7 +1674,7 @@ e401:
|
||||
*/
|
||||
for (i = 0; i < vector_length (config.add_headers); i++) {
|
||||
http_header_t *header = (http_header_t *)
|
||||
vector_getentry (config.add_headers, i, NULL);
|
||||
vector_getentry (config.add_headers, i, NULL);
|
||||
|
||||
hashmap_insert (hashofheaders,
|
||||
header->name,
|
||||
@ -1673,7 +1689,7 @@ e401:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
connptr->upstream_proxy = UPSTREAM_HOST (request->host);
|
||||
connptr->upstream_proxy = UPSTREAM_REQUEST (request);
|
||||
if (connptr->upstream_proxy != NULL) {
|
||||
if (connect_to_upstream (connptr, request) < 0) {
|
||||
goto fail;
|
||||
@ -1704,7 +1720,7 @@ e401:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!connptr->connect_method || UPSTREAM_IS_HTTP(connptr)) {
|
||||
if (!connptr->connect_method || UPSTREAM_IS_HTTP (connptr)) {
|
||||
if (process_server_headers (connptr) < 0) {
|
||||
update_stats (STAT_BADCONN);
|
||||
goto fail;
|
||||
@ -1736,8 +1752,7 @@ fail:
|
||||
* to send our data properly.
|
||||
*/
|
||||
if (get_request_entity (connptr) < 0) {
|
||||
log_message (LOG_WARNING,
|
||||
"Could not retrieve request entity");
|
||||
log_message (LOG_WARNING, "Could not retrieve request entity");
|
||||
indicate_http_error (connptr, 400, "Bad Request",
|
||||
"detail",
|
||||
"Could not retrieve the request entity "
|
||||
|
@ -37,6 +37,7 @@ struct request_s {
|
||||
char *method;
|
||||
char *protocol;
|
||||
|
||||
char *url;
|
||||
char *host;
|
||||
uint16_t port;
|
||||
|
||||
|
159
src/upstream.c
159
src/upstream.c
@ -31,27 +31,36 @@
|
||||
#include "basicauth.h"
|
||||
|
||||
#ifdef UPSTREAM_SUPPORT
|
||||
const char *
|
||||
proxy_type_name(proxy_type type)
|
||||
const char *proxy_type_name (proxy_type type)
|
||||
{
|
||||
switch(type) {
|
||||
case PT_NONE: return "none";
|
||||
case PT_HTTP: return "http";
|
||||
case PT_SOCKS4: return "socks4";
|
||||
case PT_SOCKS5: return "socks5";
|
||||
default: return "unknown";
|
||||
}
|
||||
switch (type) {
|
||||
case PT_NONE:
|
||||
return "none";
|
||||
case PT_HTTP:
|
||||
return "http";
|
||||
case PT_SOCKS4:
|
||||
return "socks4";
|
||||
case PT_SOCKS5:
|
||||
return "socks5";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an upstream struct from input data.
|
||||
*/
|
||||
static struct upstream *upstream_build (const char *host, int port, const char *domain,
|
||||
const char *user, const char *pass,
|
||||
proxy_type type)
|
||||
static struct upstream *upstream_build (const char *host, int port,
|
||||
const char *domain, const char *user,
|
||||
const char *pass, proxy_type type)
|
||||
{
|
||||
char *ptr;
|
||||
struct upstream *up;
|
||||
#ifdef UPSTREAM_REGEX
|
||||
int cflags = REG_NEWLINE | REG_NOSUB;
|
||||
int rflag = 0;
|
||||
const char *rptr = NULL;
|
||||
#endif
|
||||
|
||||
up = (struct upstream *) safemalloc (sizeof (struct upstream));
|
||||
if (!up) {
|
||||
@ -62,12 +71,46 @@ static struct upstream *upstream_build (const char *host, int port, const char *
|
||||
|
||||
up->type = type;
|
||||
up->host = up->domain = up->ua.user = up->pass = NULL;
|
||||
#ifdef UPSTREAM_REGEX
|
||||
up->pat = NULL;
|
||||
up->cpat = NULL;
|
||||
if (domain && !strncasecmp (domain, "regex(", 6)) { /* basic regex case senstive */
|
||||
rflag = 1;
|
||||
rptr = domain + 6;
|
||||
}
|
||||
if (domain && !strncasecmp (domain, "regexe(", 7)) { /* extended regex case senstive */
|
||||
rflag = 1;
|
||||
rptr = domain + 7;
|
||||
cflags |= REG_EXTENDED;
|
||||
}
|
||||
if (domain && !strncasecmp (domain, "regexi(", 7)) { /* basic regex case insenstive */
|
||||
rflag = 1;
|
||||
rptr = domain + 7;
|
||||
cflags |= REG_ICASE;
|
||||
}
|
||||
if ((domain && (!strncasecmp (domain, "regexie(", 8) || /* extended regex case insenstive */
|
||||
!strncasecmp (domain, "regexei(", 8)))) { /* extended regex case insenstive */
|
||||
rflag = 1;
|
||||
rptr = domain + 8;
|
||||
cflags |= REG_ICASE;
|
||||
cflags |= REG_ICASE;
|
||||
}
|
||||
if (rflag) {
|
||||
if (domain[strlen (domain) - 1] != ')') {
|
||||
log_message (LOG_WARNING, "Bad regex: %s", domain);
|
||||
goto fail;
|
||||
} else {
|
||||
up->pat = safestrdup (rptr);
|
||||
up->pat[strlen (rptr) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
#endif
|
||||
up->ip = up->mask = 0;
|
||||
if (user) {
|
||||
if (type == PT_HTTP) {
|
||||
char b[BASE64ENC_BYTES((256+2)-1) + 1];
|
||||
char b[BASE64ENC_BYTES ((256 + 2) - 1) + 1];
|
||||
ssize_t ret;
|
||||
ret = basicauth_string(user, pass, b, sizeof b);
|
||||
ret = basicauth_string (user, pass, b, sizeof b);
|
||||
if (ret == 0) {
|
||||
log_message (LOG_ERR,
|
||||
"User / pass in upstream config too long");
|
||||
@ -91,35 +134,52 @@ static struct upstream *upstream_build (const char *host, int port, const char *
|
||||
up->port = port;
|
||||
|
||||
log_message (LOG_INFO, "Added upstream %s %s:%d for [default]",
|
||||
proxy_type_name(type), host, port);
|
||||
proxy_type_name (type), host, port);
|
||||
} else if (host == NULL || type == PT_NONE) {
|
||||
if (!domain || domain[0] == '\0') {
|
||||
log_message (LOG_WARNING,
|
||||
"Nonsense no-upstream rule: empty domain");
|
||||
goto fail;
|
||||
}
|
||||
#ifdef UPSTREAM_REGEX
|
||||
if (!rflag) {
|
||||
#endif
|
||||
ptr = strchr (domain, '/');
|
||||
if (ptr) {
|
||||
struct in_addr addrstruct;
|
||||
|
||||
ptr = strchr (domain, '/');
|
||||
if (ptr) {
|
||||
struct in_addr addrstruct;
|
||||
*ptr = '\0';
|
||||
if (inet_aton (domain, &addrstruct) != 0) {
|
||||
up->ip = ntohl (addrstruct.s_addr);
|
||||
*ptr++ = '/';
|
||||
|
||||
*ptr = '\0';
|
||||
if (inet_aton (domain, &addrstruct) != 0) {
|
||||
up->ip = ntohl (addrstruct.s_addr);
|
||||
*ptr++ = '/';
|
||||
|
||||
if (strchr (ptr, '.')) {
|
||||
if (inet_aton (ptr, &addrstruct) != 0)
|
||||
if (strchr (ptr, '.')) {
|
||||
if (inet_aton (ptr, &addrstruct)
|
||||
!= 0)
|
||||
up->mask =
|
||||
ntohl
|
||||
(addrstruct.s_addr);
|
||||
} else {
|
||||
up->mask =
|
||||
ntohl (addrstruct.s_addr);
|
||||
} else {
|
||||
up->mask =
|
||||
~((1 << (32 - atoi (ptr))) - 1);
|
||||
~((1 << (32 - atoi (ptr))) -
|
||||
1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
up->domain = safestrdup (domain);
|
||||
}
|
||||
#ifdef UPSTREAM_REGEX
|
||||
} else {
|
||||
up->domain = safestrdup (domain);
|
||||
int err = 0;
|
||||
up->cpat = (regex_t *) safemalloc (sizeof (regex_t));
|
||||
err = regcomp (up->cpat, up->pat, cflags);
|
||||
if (err != 0) {
|
||||
log_message (LOG_WARNING,
|
||||
"Bad regex: %s", up->pat);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
log_message (LOG_INFO, "Added no-upstream for %s", domain);
|
||||
} else {
|
||||
@ -133,9 +193,20 @@ static struct upstream *upstream_build (const char *host, int port, const char *
|
||||
up->host = safestrdup (host);
|
||||
up->port = port;
|
||||
up->domain = safestrdup (domain);
|
||||
|
||||
#ifdef UPSTREAM_REGEX
|
||||
if (rflag) {
|
||||
int err = 0;
|
||||
up->cpat = (regex_t *) safemalloc (sizeof (regex_t));
|
||||
err = regcomp (up->cpat, up->pat, cflags);
|
||||
if (err != 0) {
|
||||
log_message (LOG_WARNING,
|
||||
"Bad regex: %s", up->pat);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
log_message (LOG_INFO, "Added upstream %s %s:%d for %s",
|
||||
proxy_type_name(type), host, port, domain);
|
||||
proxy_type_name (type), host, port, domain);
|
||||
}
|
||||
|
||||
return up;
|
||||
@ -145,6 +216,10 @@ fail:
|
||||
safefree (up->pass);
|
||||
safefree (up->host);
|
||||
safefree (up->domain);
|
||||
#ifdef UPSTREAM_REGEX
|
||||
safefree (up->pat);
|
||||
safefree (up->cpat);
|
||||
#endif
|
||||
safefree (up);
|
||||
|
||||
return NULL;
|
||||
@ -200,12 +275,27 @@ upstream_cleanup:
|
||||
/*
|
||||
* Check if a host is in the upstream list
|
||||
*/
|
||||
struct upstream *upstream_get (char *host, struct upstream *up)
|
||||
struct upstream *upstream_get (struct request_s *request, struct upstream *up)
|
||||
{
|
||||
char *host = request->host;
|
||||
|
||||
in_addr_t my_ip = INADDR_NONE;
|
||||
|
||||
while (up) {
|
||||
#ifdef UPSTREAM_REGEX
|
||||
if (up->cpat) {
|
||||
int result;
|
||||
char *url = request->url;
|
||||
result =
|
||||
regexec (up->cpat, url, (size_t) 0,
|
||||
(regmatch_t *) 0, 0);
|
||||
|
||||
if (result == 0)
|
||||
break; /* regex match */
|
||||
} else if (up->domain) {
|
||||
#else
|
||||
if (up->domain) {
|
||||
#endif
|
||||
if (strcasecmp (host, up->domain) == 0)
|
||||
break; /* exact match */
|
||||
|
||||
@ -239,7 +329,8 @@ struct upstream *upstream_get (char *host, struct upstream *up)
|
||||
|
||||
if (up)
|
||||
log_message (LOG_INFO, "Found upstream proxy %s %s:%d for %s",
|
||||
proxy_type_name(up->type), up->host, up->port, host);
|
||||
proxy_type_name (up->type), up->host, up->port,
|
||||
host);
|
||||
else
|
||||
log_message (LOG_INFO, "No upstream proxy for %s", host);
|
||||
|
||||
|
@ -26,16 +26,17 @@
|
||||
#define _TINYPROXY_UPSTREAM_H_
|
||||
|
||||
#include "common.h"
|
||||
#include "reqs.h"
|
||||
|
||||
/*
|
||||
* Even if upstream support is not compiled into tinyproxy, this
|
||||
* structure still needs to be defined.
|
||||
*/
|
||||
typedef enum proxy_type {
|
||||
PT_NONE = 0,
|
||||
PT_HTTP,
|
||||
PT_SOCKS4,
|
||||
PT_SOCKS5
|
||||
PT_NONE = 0,
|
||||
PT_HTTP,
|
||||
PT_SOCKS4,
|
||||
PT_SOCKS5
|
||||
} proxy_type;
|
||||
|
||||
struct upstream {
|
||||
@ -50,14 +51,19 @@ struct upstream {
|
||||
int port;
|
||||
in_addr_t ip, mask;
|
||||
proxy_type type;
|
||||
#if defined(UPSTREAM_SUPPORT) && defined(UPSTREAM_REGEX)
|
||||
char *pat;
|
||||
regex_t *cpat;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef UPSTREAM_SUPPORT
|
||||
const char *proxy_type_name(proxy_type type);
|
||||
const char *proxy_type_name (proxy_type type);
|
||||
extern void upstream_add (const char *host, int port, const char *domain,
|
||||
const char *user, const char *pass,
|
||||
proxy_type type, struct upstream **upstream_list);
|
||||
extern struct upstream *upstream_get (char *host, struct upstream *up);
|
||||
extern struct upstream *upstream_get (struct request_s *request,
|
||||
struct upstream *up);
|
||||
extern void free_upstream_list (struct upstream *up);
|
||||
#endif /* UPSTREAM_SUPPORT */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user