Add proxy list

This commit is contained in:
Markus Moeller 2020-01-10 14:34:33 +00:00
parent 93e9c156e8
commit d72ad621e5
32 changed files with 680 additions and 519 deletions

View File

@ -72,6 +72,11 @@ The possible keywords and their descriptions are as follows:
The maximum number of seconds of inactivity a connection is The maximum number of seconds of inactivity a connection is
allowed to have before it is closed by Tinyproxy. allowed to have before it is closed by Tinyproxy.
*DeadTime*::
The maximum number of seconds of marking a proxy dead i.e. proxy
won't be used for a new connections by Tinyproxy during the deadtime.
*ErrorFile*:: *ErrorFile*::
This parameter controls which HTML file Tinyproxy returns when a This parameter controls which HTML file Tinyproxy returns when a
@ -153,12 +158,16 @@ The possible keywords and their descriptions are as follows:
rules exist: rules exist:
* 'upstream type host:port' turns proxy upstream support on generally. * 'upstream type host:port' turns proxy upstream support on generally.
host:port can be a list seperated by | e.g. host1:port1|host2:port2.
* 'upstream type user:pass@host:port' does the same, but uses the * 'upstream type user:pass@host:port' does the same, but uses the
supplied credentials for authentication. supplied credentials for authentication. host:port can be a list
seperated by | e.g. host1:port1|host2:port2. Same user:pass will be
used for the list.
* 'upstream type host:port "site_spec"' turns on the upstream proxy * 'upstream type host:port "site_spec"' turns on the upstream proxy
for the sites matching `site_spec`. for the sites matching `site_spec`. host:port can be a list
seperated by | e.g. host1:port1|host2:port2.
`type` can be one of `http`, `socks4`, `socks5`, `none`. `type` can be one of `http`, `socks4`, `socks5`, `none`.
@ -173,6 +182,11 @@ The possible keywords and their descriptions are as follows:
* '.' matches any host with no domain (in 'empty' domain) * '.' matches any host with no domain (in 'empty' domain)
* 'IP/bits' matches network/mask * 'IP/bits' matches network/mask
* 'IP/mask' matches network/mask * 'IP/mask' matches network/mask
* 'regex(<pat>)' matches against basic case senstive regular expression
* 'regexe(<pat>)' matches against extended case senstive regular expression
* 'regexi(<pat>)' matches against basic case insenstive regular expression
* 'regexei(<pat>)' matches against extended case insenstive regular expression
* 'regexie(<pat>)' matches against extended case insenstive regular expression
*MaxClients*:: *MaxClients*::

View File

@ -111,7 +111,7 @@ fill_netmask_array (char *bitmask_string, int v6,
/** /**
* If the access list has not been set up, create it. * If the access list has not been set up, create it.
*/ */
static int init_access_list(vector_t *access_list) static int init_access_list (vector_t *access_list)
{ {
if (!*access_list) { if (!*access_list) {
*access_list = vector_create (); *access_list = vector_create ();
@ -143,7 +143,7 @@ insert_acl (char *location, acl_access_t access_type, vector_t *access_list)
assert (location != NULL); assert (location != NULL);
ret = init_access_list(access_list); ret = init_access_list (access_list);
if (ret != 0) { if (ret != 0) {
return -1; return -1;
} }
@ -170,7 +170,7 @@ insert_acl (char *location, acl_access_t access_type, vector_t *access_list)
*/ */
p = strchr (location, '/'); p = strchr (location, '/');
if (p != NULL) { if (p != NULL) {
char dst[sizeof(struct in6_addr)]; char dst[sizeof (struct in6_addr)];
int v6; int v6;
/* /*
@ -185,7 +185,7 @@ insert_acl (char *location, acl_access_t access_type, vector_t *access_list)
/* Check if the IP address before the netmask is /* Check if the IP address before the netmask is
* an IPv6 address */ * an IPv6 address */
if (inet_pton(AF_INET6, location, dst) > 0) if (inet_pton (AF_INET6, location, dst) > 0)
v6 = 1; v6 = 1;
else else
v6 = 0; v6 = 0;
@ -197,7 +197,7 @@ insert_acl (char *location, acl_access_t access_type, vector_t *access_list)
for (i = 0; i < IPV6_LEN; i++) for (i = 0; i < IPV6_LEN; i++)
acl.address.ip.network[i] = ip_dst[i] & acl.address.ip.network[i] = ip_dst[i] &
acl.address.ip.mask[i]; acl.address.ip.mask[i];
} else { } else {
/* In all likelihood a string */ /* In all likelihood a string */
acl.type = ACL_STRING; acl.type = ACL_STRING;

View File

@ -19,7 +19,7 @@
#include "base64.h" #include "base64.h"
static const char base64_tbl[64] = static const char base64_tbl[64] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/* /*
rofl0r's base64 impl (taken from libulz) rofl0r's base64 impl (taken from libulz)
@ -27,31 +27,30 @@ static const char base64_tbl[64] =
dst needs to be at least BASE64ENC_BYTES(count) + 1 bytes in size. dst needs to be at least BASE64ENC_BYTES(count) + 1 bytes in size.
the string in dst will be zero-terminated. the string in dst will be zero-terminated.
*/ */
void base64enc(char *dst, const void* src, size_t count) void base64enc (char *dst, const void *src, size_t count)
{ {
unsigned const char *s = src; unsigned const char *s = src;
char* d = dst; char *d = dst;
while(count) { while (count) {
int i = 0, n = *s << 16; int i = 0, n = *s << 16;
s++; s++;
count--; count--;
if(count) { if (count) {
n |= *s << 8; n |= *s << 8;
s++; s++;
count--; count--;
i++; i++;
} }
if(count) { if (count) {
n |= *s; n |= *s;
s++; s++;
count--; count--;
i++; i++;
} }
*d++ = base64_tbl[(n >> 18) & 0x3f]; *d++ = base64_tbl[(n >> 18) & 0x3f];
*d++ = base64_tbl[(n >> 12) & 0x3f]; *d++ = base64_tbl[(n >> 12) & 0x3f];
*d++ = i ? base64_tbl[(n >> 6) & 0x3f] : '='; *d++ = i ? base64_tbl[(n >> 6) & 0x3f] : '=';
*d++ = i == 2 ? base64_tbl[n & 0x3f] : '='; *d++ = i == 2 ? base64_tbl[n & 0x3f] : '=';
} }
*d = 0; *d = 0;
} }

View File

@ -23,7 +23,6 @@
/* calculates number of bytes base64-encoded stream of N bytes will take. */ /* calculates number of bytes base64-encoded stream of N bytes will take. */
#define BASE64ENC_BYTES(N) (((N+2)/3)*4) #define BASE64ENC_BYTES(N) (((N+2)/3)*4)
void base64enc(char *dst, const void* src, size_t count); void base64enc (char *dst, const void *src, size_t count);
#endif #endif

View File

@ -32,29 +32,31 @@
* -1 if user/pass missing * -1 if user/pass missing
* 0 if user/pass too long * 0 if user/pass too long
*/ */
ssize_t basicauth_string(const char *user, const char *pass, ssize_t basicauth_string (const char *user, const char *pass,
char *buf, size_t bufsize) char *buf, size_t bufsize)
{ {
char tmp[256+2]; char tmp[256 + 2];
int l; int l;
if (!user || !pass) return -1; if (!user || !pass)
l = snprintf(tmp, sizeof tmp, "%s:%s", user, pass); return -1;
if (l < 0 || l >= (ssize_t) sizeof tmp) return 0; l = snprintf (tmp, sizeof tmp, "%s:%s", user, pass);
if (bufsize < (BASE64ENC_BYTES((unsigned)l) + 1)) return 0; if (l < 0 || l >= (ssize_t) sizeof tmp)
base64enc(buf, tmp, l); return 0;
return BASE64ENC_BYTES(l); if (bufsize < (BASE64ENC_BYTES ((unsigned) l) + 1))
return 0;
base64enc (buf, tmp, l);
return BASE64ENC_BYTES (l);
} }
/* /*
* Add entry to the basicauth list * Add entry to the basicauth list
*/ */
void basicauth_add (vector_t authlist, void basicauth_add (vector_t authlist, const char *user, const char *pass)
const char *user, const char *pass)
{ {
char b[BASE64ENC_BYTES((256+2)-1) + 1]; char b[BASE64ENC_BYTES ((256 + 2) - 1) + 1];
ssize_t ret; ssize_t ret;
ret = basicauth_string(user, pass, b, sizeof b); ret = basicauth_string (user, pass, b, sizeof b);
if (ret == -1) { if (ret == -1) {
log_message (LOG_WARNING, log_message (LOG_WARNING,
"Illegal basicauth rule: missing user or pass"); "Illegal basicauth rule: missing user or pass");
@ -65,14 +67,13 @@ void basicauth_add (vector_t authlist,
return; return;
} }
if (vector_append(authlist, b, ret + 1) == -ENOMEM) { if (vector_append (authlist, b, ret + 1) == -ENOMEM) {
log_message (LOG_ERR, log_message (LOG_ERR,
"Unable to allocate memory in basicauth_add()"); "Unable to allocate memory in basicauth_add()");
return; return;
} }
log_message (LOG_INFO, log_message (LOG_INFO, "Added basic auth user : %s", user);
"Added basic auth user : %s", user);
} }
/* /*
@ -84,15 +85,16 @@ int basicauth_check (vector_t authlist, const char *authstring)
{ {
ssize_t vl, i; ssize_t vl, i;
size_t el; size_t el;
const char* entry; const char *entry;
vl = vector_length (authlist); vl = vector_length (authlist);
if (vl == -EINVAL) return 0; if (vl == -EINVAL)
return 0;
for (i = 0; i < vl; i++) { for (i = 0; i < vl; i++) {
entry = vector_getentry (authlist, i, &el); entry = vector_getentry (authlist, i, &el);
if (strcmp (authstring, entry) == 0) if (strcmp (authstring, entry) == 0)
return 1; return 1;
} }
return 0; return 0;
} }

View File

@ -24,11 +24,11 @@
#include <stddef.h> #include <stddef.h>
#include "vector.h" #include "vector.h"
extern ssize_t basicauth_string(const char *user, const char *pass, extern ssize_t basicauth_string (const char *user, const char *pass,
char *buf, size_t bufsize); char *buf, size_t bufsize);
extern void basicauth_add (vector_t authlist, extern void basicauth_add (vector_t authlist,
const char *user, const char *pass); const char *user, const char *pass);
extern int basicauth_check (vector_t authlist, const char *authstring); extern int basicauth_check (vector_t authlist, const char *authstring);

View File

@ -244,9 +244,9 @@ ssize_t read_buffer (int fd, struct buffer_s * buffptr)
#ifdef EWOULDBLOCK #ifdef EWOULDBLOCK
case EWOULDBLOCK: case EWOULDBLOCK:
#else #else
# ifdef EAGAIN #ifdef EAGAIN
case EAGAIN: case EAGAIN:
# endif #endif
#endif #endif
case EINTR: case EINTR:
bytesin = 0; bytesin = 0;
@ -254,7 +254,7 @@ ssize_t read_buffer (int fd, struct buffer_s * buffptr)
default: default:
log_message (LOG_ERR, log_message (LOG_ERR,
"read_buffer: read() failed on fd %d: %s", "read_buffer: read() failed on fd %d: %s",
fd, strerror(errno)); fd, strerror (errno));
bytesin = -1; bytesin = -1;
break; break;
} }
@ -298,9 +298,9 @@ ssize_t write_buffer (int fd, struct buffer_s * buffptr)
#ifdef EWOULDBLOCK #ifdef EWOULDBLOCK
case EWOULDBLOCK: case EWOULDBLOCK:
#else #else
# ifdef EAGAIN #ifdef EAGAIN
case EAGAIN: case EAGAIN:
# endif #endif
#endif #endif
case EINTR: case EINTR:
return 0; return 0;

View File

@ -192,7 +192,7 @@ static void child_main (struct child_s *ptr)
int ret; int ret;
cliaddr = (struct sockaddr *) cliaddr = (struct sockaddr *)
safemalloc (sizeof(struct sockaddr_storage)); safemalloc (sizeof (struct sockaddr_storage));
if (!cliaddr) { if (!cliaddr) {
log_message (LOG_CRIT, log_message (LOG_CRIT,
"Could not allocate memory for child address."); "Could not allocate memory for child address.");
@ -200,7 +200,7 @@ static void child_main (struct child_s *ptr)
} }
ptr->connects = 0; ptr->connects = 0;
srand(time(NULL)); srand (time (NULL));
/* /*
* We have to wait for connections on multiple fds, * We have to wait for connections on multiple fds,
@ -210,45 +210,46 @@ static void child_main (struct child_s *ptr)
int listenfd = -1; int listenfd = -1;
FD_ZERO(&rfds); FD_ZERO (&rfds);
for (i = 0; i < vector_length(listen_fds); i++) { for (i = 0; i < vector_length (listen_fds); i++) {
int *fd = (int *) vector_getentry(listen_fds, i, NULL); int *fd = (int *) vector_getentry (listen_fds, i, NULL);
ret = socket_nonblocking(*fd); ret = socket_nonblocking (*fd);
if (ret != 0) { if (ret != 0) {
log_message(LOG_ERR, "Failed to set the listening " log_message (LOG_ERR,
"socket %d to non-blocking: %s", "Failed to set the listening "
fd, strerror(errno)); "socket %d to non-blocking: %s",
exit(1); fd, strerror (errno));
exit (1);
} }
FD_SET(*fd, &rfds); FD_SET (*fd, &rfds);
maxfd = max(maxfd, *fd); maxfd = max (maxfd, *fd);
} }
ptr->status = T_WAITING; ptr->status = T_WAITING;
clilen = sizeof(struct sockaddr_storage); clilen = sizeof (struct sockaddr_storage);
ret = select(maxfd + 1, &rfds, NULL, NULL, NULL); ret = select (maxfd + 1, &rfds, NULL, NULL, NULL);
if (ret == -1) { if (ret == -1) {
if (errno == EINTR) { if (errno == EINTR) {
continue; continue;
} }
log_message (LOG_ERR, "error calling select: %s", log_message (LOG_ERR, "error calling select: %s",
strerror(errno)); strerror (errno));
exit(1); exit (1);
} else if (ret == 0) { } else if (ret == 0) {
log_message (LOG_WARNING, "Strange: select returned 0 " log_message (LOG_WARNING, "Strange: select returned 0 "
"but we did not specify a timeout..."); "but we did not specify a timeout...");
continue; continue;
} }
for (i = 0; i < vector_length(listen_fds); i++) { for (i = 0; i < vector_length (listen_fds); i++) {
int *fd = (int *) vector_getentry(listen_fds, i, NULL); int *fd = (int *) vector_getentry (listen_fds, i, NULL);
if (FD_ISSET(*fd, &rfds)) { if (FD_ISSET (*fd, &rfds)) {
/* /*
* only accept the connection on the first * only accept the connection on the first
* fd that we find readable. - fair? * fd that we find readable. - fair?
@ -259,17 +260,17 @@ static void child_main (struct child_s *ptr)
} }
if (listenfd == -1) { if (listenfd == -1) {
log_message(LOG_WARNING, "Strange: None of our listen " log_message (LOG_WARNING, "Strange: None of our listen "
"fds was readable after select"); "fds was readable after select");
continue; continue;
} }
ret = socket_blocking(listenfd); ret = socket_blocking (listenfd);
if (ret != 0) { if (ret != 0) {
log_message(LOG_ERR, "Failed to set listening " log_message (LOG_ERR, "Failed to set listening "
"socket %d to blocking for accept: %s", "socket %d to blocking for accept: %s",
listenfd, strerror(errno)); listenfd, strerror (errno));
exit(1); exit (1);
} }
/* /*
@ -539,11 +540,10 @@ void child_kill_children (int sig)
} }
} }
/** /**
* Listen on the various configured interfaces * Listen on the various configured interfaces
*/ */
int child_listening_sockets(vector_t listen_addrs, uint16_t port) int child_listening_sockets (vector_t listen_addrs, uint16_t port)
{ {
int ret; int ret;
ssize_t i; ssize_t i;
@ -551,7 +551,7 @@ int child_listening_sockets(vector_t listen_addrs, uint16_t port)
assert (port > 0); assert (port > 0);
if (listen_fds == NULL) { if (listen_fds == NULL) {
listen_fds = vector_create(); listen_fds = vector_create ();
if (listen_fds == NULL) { if (listen_fds == NULL) {
log_message (LOG_ERR, "Could not create the list " log_message (LOG_ERR, "Could not create the list "
"of listening fds"); "of listening fds");
@ -559,28 +559,26 @@ int child_listening_sockets(vector_t listen_addrs, uint16_t port)
} }
} }
if ((listen_addrs == NULL) || if ((listen_addrs == NULL) || (vector_length (listen_addrs) == 0)) {
(vector_length(listen_addrs) == 0))
{
/* /*
* no Listen directive: * no Listen directive:
* listen on the wildcard address(es) * listen on the wildcard address(es)
*/ */
ret = listen_sock(NULL, port, listen_fds); ret = listen_sock (NULL, port, listen_fds);
return ret; return ret;
} }
for (i = 0; i < vector_length(listen_addrs); i++) { for (i = 0; i < vector_length (listen_addrs); i++) {
const char *addr; const char *addr;
addr = (char *)vector_getentry(listen_addrs, i, NULL); addr = (char *) vector_getentry (listen_addrs, i, NULL);
if (addr == NULL) { if (addr == NULL) {
log_message(LOG_WARNING, log_message (LOG_WARNING,
"got NULL from listen_addrs - skipping"); "got NULL from listen_addrs - skipping");
continue; continue;
} }
ret = listen_sock(addr, port, listen_fds); ret = listen_sock (addr, port, listen_fds);
if (ret != 0) { if (ret != 0) {
return ret; return ret;
} }
@ -593,12 +591,12 @@ void child_close_sock (void)
{ {
ssize_t i; ssize_t i;
for (i = 0; i < vector_length(listen_fds); i++) { for (i = 0; i < vector_length (listen_fds); i++) {
int *fd = (int *) vector_getentry(listen_fds, i, NULL); int *fd = (int *) vector_getentry (listen_fds, i, NULL);
close (*fd); close (*fd);
} }
vector_delete(listen_fds); vector_delete (listen_fds);
listen_fds = NULL; listen_fds = NULL;
} }

View File

@ -26,7 +26,7 @@
#define COMMON_HEADER_H #define COMMON_HEADER_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include <config.h> #include <config.h>
#endif #endif
/* /*
@ -42,57 +42,57 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
/* standard POSIX headers - they need to be there as well. */ /* standard POSIX headers - they need to be there as well. */
# include <errno.h> #include <errno.h>
# include <fcntl.h> #include <fcntl.h>
# include <netdb.h> #include <netdb.h>
# include <signal.h> #include <signal.h>
# include <stdarg.h> #include <stdarg.h>
# include <strings.h> #include <strings.h>
# include <syslog.h> #include <syslog.h>
# include <wchar.h> #include <wchar.h>
# include <wctype.h> #include <wctype.h>
# include <sys/mman.h> #include <sys/mman.h>
# include <sys/select.h> #include <sys/select.h>
# include <sys/socket.h> #include <sys/socket.h>
# include <sys/stat.h> #include <sys/stat.h>
# include <sys/types.h> #include <sys/types.h>
# include <sys/wait.h> #include <sys/wait.h>
# include <sys/uio.h> #include <sys/uio.h>
# include <sys/un.h> #include <sys/un.h>
# include <sys/time.h> #include <sys/time.h>
# include <time.h> #include <time.h>
# include <inttypes.h> #include <inttypes.h>
# include <sys/resource.h> #include <sys/resource.h>
# include <netinet/in.h> #include <netinet/in.h>
# include <assert.h> #include <assert.h>
# include <arpa/inet.h> #include <arpa/inet.h>
# include <grp.h> #include <grp.h>
# include <pwd.h> #include <pwd.h>
# include <regex.h> #include <regex.h>
/* rest - some oddball headers */ /* rest - some oddball headers */
#ifdef HAVE_VALUES_H #ifdef HAVE_VALUES_H
# include <values.h> #include <values.h>
#endif #endif
#ifdef HAVE_SYS_IOCTL_H #ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h> #include <sys/ioctl.h>
#endif #endif
#ifdef HAVE_ALLOCA_H #ifdef HAVE_ALLOCA_H
# include <alloca.h> #include <alloca.h>
#endif #endif
#ifdef HAVE_MEMORY_H #ifdef HAVE_MEMORY_H
# include <memory.h> #include <memory.h>
#endif #endif
#ifdef HAVE_MALLOC_H #ifdef HAVE_MALLOC_H
# include <malloc.h> #include <malloc.h>
#endif #endif
#ifdef HAVE_SYSEXITS_H #ifdef HAVE_SYSEXITS_H
# include <sysexits.h> #include <sysexits.h>
#endif #endif
/* /*
@ -100,13 +100,13 @@
* cause any problems. * cause any problems.
*/ */
#ifndef MSG_NOSIGNAL #ifndef MSG_NOSIGNAL
# define MSG_NOSIGNAL (0) #define MSG_NOSIGNAL (0)
#endif #endif
#ifndef SHUT_RD /* these three Posix.1g names are quite new */ #ifndef SHUT_RD /* these three Posix.1g names are quite new */
# define SHUT_RD 0 /* shutdown for reading */ #define SHUT_RD 0 /* shutdown for reading */
# define SHUT_WR 1 /* shutdown for writing */ #define SHUT_WR 1 /* shutdown for writing */
# define SHUT_RDWR 2 /* shutdown for reading and writing */ #define SHUT_RDWR 2 /* shutdown for reading and writing */
#endif #endif
#define MAXLISTEN 1024 /* Max number of connections */ #define MAXLISTEN 1024 /* Max number of connections */
@ -115,19 +115,19 @@
* SunOS doesn't have INADDR_NONE defined. * SunOS doesn't have INADDR_NONE defined.
*/ */
#ifndef INADDR_NONE #ifndef INADDR_NONE
# define INADDR_NONE -1 #define INADDR_NONE -1
#endif #endif
/* Define boolean values */ /* Define boolean values */
#ifndef FALSE #ifndef FALSE
# define FALSE 0 #define FALSE 0
# define TRUE (!FALSE) #define TRUE (!FALSE)
#endif #endif
/* Useful function macros */ /* Useful function macros */
#if !defined(min) || !defined(max) #if !defined(min) || !defined(max)
# define min(a,b) ((a) < (b) ? (a) : (b)) #define min(a,b) ((a) < (b) ? (a) : (b))
# define max(a,b) ((a) > (b) ? (a) : (b)) #define max(a,b) ((a) > (b) ? (a) : (b))
#endif #endif
#endif #endif

View File

@ -80,13 +80,14 @@
#define IPV6MASK "(" IPV6 "(/[[:digit:]]+)?)" #define IPV6MASK "(" IPV6 "(/[[:digit:]]+)?)"
#define BEGIN "^[[:space:]]*" #define BEGIN "^[[:space:]]*"
#define END "[[:space:]]*$" #define END "[[:space:]]*$"
#define PIPE "\\|"
/* /*
* Limit the maximum number of substring matches to a reasonably high * Limit the maximum number of substring matches to a reasonably high
* number. Given the usual structure of the configuration file, sixteen * number. Given the usual structure of the configuration file, sixteen
* substring matches should be plenty. * substring matches should be plenty.
*/ */
#define RE_MAX_MATCHES 16 #define RE_MAX_MATCHES 50
/* /*
* All configuration handling functions are REQUIRED to be defined * All configuration handling functions are REQUIRED to be defined
@ -163,6 +164,7 @@ static HANDLE_FUNC (handle_disableviaheader);
static HANDLE_FUNC (handle_xtinyproxy); static HANDLE_FUNC (handle_xtinyproxy);
#ifdef UPSTREAM_SUPPORT #ifdef UPSTREAM_SUPPORT
static HANDLE_FUNC (handle_deadtime);
static HANDLE_FUNC (handle_upstream); static HANDLE_FUNC (handle_upstream);
static HANDLE_FUNC (handle_upstream_no); static HANDLE_FUNC (handle_upstream_no);
#endif #endif
@ -195,91 +197,89 @@ struct {
} directives[] = { } directives[] = {
/* comments */ /* comments */
{ {
BEGIN "#", handle_nop, NULL BEGIN "#", handle_nop, NULL},
}, /* blank lines */
/* blank lines */
{ {
"^[[:space:]]+$", handle_nop, NULL "^[[:space:]]+$", handle_nop, NULL},
}, /* string arguments */
/* string arguments */ STDCONF ("logfile", STR, handle_logfile),
STDCONF ("logfile", STR, handle_logfile), STDCONF ("pidfile", STR, handle_pidfile),
STDCONF ("pidfile", STR, handle_pidfile), STDCONF ("anonymous", STR, handle_anonymous),
STDCONF ("anonymous", STR, handle_anonymous), STDCONF ("viaproxyname", STR, handle_viaproxyname),
STDCONF ("viaproxyname", STR, handle_viaproxyname), STDCONF ("defaulterrorfile", STR, handle_defaulterrorfile),
STDCONF ("defaulterrorfile", STR, handle_defaulterrorfile), STDCONF ("statfile", STR, handle_statfile),
STDCONF ("statfile", STR, handle_statfile), STDCONF ("stathost", STR, handle_stathost),
STDCONF ("stathost", STR, handle_stathost), STDCONF ("xtinyproxy", BOOL, handle_xtinyproxy),
STDCONF ("xtinyproxy", BOOL, handle_xtinyproxy), /* boolean arguments */
/* boolean arguments */ STDCONF ("syslog", BOOL, handle_syslog),
STDCONF ("syslog", BOOL, handle_syslog), STDCONF ("bindsame", BOOL, handle_bindsame),
STDCONF ("bindsame", BOOL, handle_bindsame), STDCONF ("disableviaheader", BOOL, handle_disableviaheader),
STDCONF ("disableviaheader", BOOL, handle_disableviaheader), /* integer arguments */
/* integer arguments */ STDCONF ("port", INT, handle_port),
STDCONF ("port", INT, handle_port), STDCONF ("maxclients", INT, handle_maxclients),
STDCONF ("maxclients", INT, handle_maxclients), STDCONF ("maxspareservers", INT, handle_maxspareservers),
STDCONF ("maxspareservers", INT, handle_maxspareservers), STDCONF ("minspareservers", INT, handle_minspareservers),
STDCONF ("minspareservers", INT, handle_minspareservers), STDCONF ("startservers", INT, handle_startservers),
STDCONF ("startservers", INT, handle_startservers), STDCONF ("maxrequestsperchild", INT, handle_maxrequestsperchild),
STDCONF ("maxrequestsperchild", INT, handle_maxrequestsperchild), STDCONF ("timeout", INT, handle_timeout),
STDCONF ("timeout", INT, handle_timeout), #ifdef UPSTREAM_SUPPORT
STDCONF ("connectport", INT, handle_connectport), STDCONF ("deadtime", INT, handle_deadtime),
/* alphanumeric arguments */ #endif
STDCONF ("user", ALNUM, handle_user), STDCONF ("connectport", INT, handle_connectport),
STDCONF ("group", ALNUM, handle_group), /* alphanumeric arguments */
/* ip arguments */ STDCONF ("user", ALNUM, handle_user),
STDCONF ("listen", "(" IP "|" IPV6 ")", handle_listen), STDCONF ("group", ALNUM, handle_group),
STDCONF ("allow", "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")", /* ip arguments */
handle_allow), STDCONF ("listen", "(" IP "|" IPV6 ")", handle_listen),
STDCONF ("deny", "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")", STDCONF ("allow", "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")",
handle_deny), handle_allow),
STDCONF ("bind", "(" IP "|" IPV6 ")", handle_bind), STDCONF ("deny", "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")",
/* other */ handle_deny),
STDCONF ("basicauth", ALNUM WS ALNUM, handle_basicauth), STDCONF ("bind", "(" IP "|" IPV6 ")", handle_bind),
STDCONF ("errorfile", INT WS STR, handle_errorfile), /* other */
STDCONF ("addheader", STR WS STR, handle_addheader), STDCONF ("basicauth", ALNUM WS ALNUM, handle_basicauth),
STDCONF ("errorfile", INT WS STR, handle_errorfile),
STDCONF ("addheader", STR WS STR, handle_addheader),
#ifdef FILTER_ENABLE #ifdef FILTER_ENABLE
/* filtering */ /* filtering */
STDCONF ("filter", STR, handle_filter), STDCONF ("filter", STR, handle_filter),
STDCONF ("filterurls", BOOL, handle_filterurls), STDCONF ("filterurls", BOOL, handle_filterurls),
STDCONF ("filterextended", BOOL, handle_filterextended), STDCONF ("filterextended", BOOL, handle_filterextended),
STDCONF ("filterdefaultdeny", BOOL, handle_filterdefaultdeny), STDCONF ("filterdefaultdeny", BOOL, handle_filterdefaultdeny),
STDCONF ("filtercasesensitive", BOOL, handle_filtercasesensitive), STDCONF ("filtercasesensitive", BOOL, handle_filtercasesensitive),
#endif #endif
#ifdef REVERSE_SUPPORT #ifdef REVERSE_SUPPORT
/* Reverse proxy arguments */ /* Reverse proxy arguments */
STDCONF ("reversebaseurl", STR, handle_reversebaseurl), STDCONF ("reversebaseurl", STR, handle_reversebaseurl),
STDCONF ("reverseonly", BOOL, handle_reverseonly), STDCONF ("reverseonly", BOOL, handle_reverseonly),
STDCONF ("reversemagic", BOOL, handle_reversemagic), STDCONF ("reversemagic", BOOL, handle_reversemagic),
STDCONF ("reversepath", STR "(" WS STR ")?", handle_reversepath), STDCONF ("reversepath", STR "(" WS STR ")?", handle_reversepath),
#endif #endif
#ifdef UPSTREAM_SUPPORT #ifdef UPSTREAM_SUPPORT
{ {
BEGIN "(upstream)" WS "(none)" WS STR END, handle_upstream_no, NULL BEGIN "(upstream)" WS "(none)" WS STR END, handle_upstream_no, NULL},
},
{ {
BEGIN "(upstream)" WS "(http|socks4|socks5)" WS BEGIN "(upstream)" WS "(http|socks4|socks5)" WS
"(" USERNAME /*username*/ ":" PASSWORD /*password*/ "@" ")?" "(" USERNAME /*username */ ":" PASSWORD /*password */ "@"
"(" IP "|" ALNUM ")" ")?"
":" INT "(" WS STR ")?" "(" IP "|" ALNUM ")" ":" INT "(" "(" PIPE "(" IP
END, handle_upstream, NULL "|" ALNUM ")" ":" INT ")+" ")?" "(" WS STR ")?"
}, END, handle_upstream, NULL},
#endif #endif
/* loglevel */ /* loglevel */
STDCONF ("loglevel", "(critical|error|warning|notice|connect|info)", STDCONF ("loglevel", "(critical|error|warning|notice|connect|info)",
handle_loglevel) handle_loglevel)
}; };
const unsigned int ndirectives = sizeof (directives) / sizeof (directives[0]); const unsigned int ndirectives = sizeof (directives) / sizeof (directives[0]);
static void static void free_added_headers (vector_t add_headers)
free_added_headers (vector_t add_headers)
{ {
ssize_t i; ssize_t i;
for (i = 0; i < vector_length (add_headers); i++) { for (i = 0; i < vector_length (add_headers); i++) {
http_header_t *header = (http_header_t *) http_header_t *header = (http_header_t *)
vector_getentry (add_headers, i, NULL); vector_getentry (add_headers, i, NULL);
safefree (header->name); safefree (header->name);
safefree (header->value); safefree (header->value);
@ -288,25 +288,25 @@ free_added_headers (vector_t add_headers)
vector_delete (add_headers); vector_delete (add_headers);
} }
static void free_config (struct config_s *conf) void free_config (struct config_s *conf)
{ {
safefree (conf->config_file); safefree (conf->config_file);
safefree (conf->logf_name); safefree (conf->logf_name);
safefree (conf->stathost); safefree (conf->stathost);
safefree (conf->user); safefree (conf->user);
safefree (conf->group); safefree (conf->group);
vector_delete(conf->listen_addrs); vector_delete (conf->listen_addrs);
vector_delete(conf->basicauth_list); vector_delete (conf->basicauth_list);
#ifdef FILTER_ENABLE #ifdef FILTER_ENABLE
safefree (conf->filter); safefree (conf->filter);
#endif /* FILTER_ENABLE */ #endif /* FILTER_ENABLE */
#ifdef REVERSE_SUPPORT #ifdef REVERSE_SUPPORT
free_reversepath_list(conf->reversepath_list); free_reversepath_list (conf->reversepath_list);
safefree (conf->reversebaseurl); safefree (conf->reversebaseurl);
#endif #endif
#ifdef UPSTREAM_SUPPORT #ifdef UPSTREAM_SUPPORT
free_upstream_list (conf->upstream_list); free_upstream_list (conf->upstream_list);
#endif /* UPSTREAM_SUPPORT */ #endif /* UPSTREAM_SUPPORT */
safefree (conf->pidpath); safefree (conf->pidpath);
safefree (conf->bind_address); safefree (conf->bind_address);
safefree (conf->via_proxy_name); safefree (conf->via_proxy_name);
@ -318,7 +318,7 @@ static void free_config (struct config_s *conf)
free_connect_ports_list (conf->connect_ports); free_connect_ports_list (conf->connect_ports);
hashmap_delete (conf->anonymous_map); hashmap_delete (conf->anonymous_map);
memset (conf, 0, sizeof(*conf)); memset (conf, 0, sizeof (*conf));
} }
/* /*
@ -327,8 +327,7 @@ static void free_config (struct config_s *conf)
* *
* Returns 0 on success; negative upon failure. * Returns 0 on success; negative upon failure.
*/ */
int int config_compile_regex (void)
config_compile_regex (void)
{ {
unsigned int i, r; unsigned int i, r;
@ -356,8 +355,7 @@ config_compile_regex (void)
* Frees pre-compiled regular expressions used by the configuration * Frees pre-compiled regular expressions used by the configuration
* file. This function is registered to be automatically called at exit. * file. This function is registered to be automatically called at exit.
*/ */
static void static void config_free_regex (void)
config_free_regex (void)
{ {
unsigned int i; unsigned int i;
@ -384,7 +382,6 @@ static int check_match (struct config_s *conf, const char *line)
unsigned int i; unsigned int i;
assert (ndirectives > 0); assert (ndirectives > 0);
for (i = 0; i != ndirectives; ++i) { for (i = 0; i != ndirectives; ++i) {
assert (directives[i].cre); assert (directives[i].cre);
if (!regexec if (!regexec
@ -476,17 +473,16 @@ static void initialize_with_defaults (struct config_s *conf,
if (defaults->listen_addrs) { if (defaults->listen_addrs) {
ssize_t i; ssize_t i;
conf->listen_addrs = vector_create(); conf->listen_addrs = vector_create ();
for (i=0; i < vector_length(defaults->listen_addrs); i++) { for (i = 0; i < vector_length (defaults->listen_addrs); i++) {
char *addr; char *addr;
size_t size; size_t size;
addr = (char *)vector_getentry(defaults->listen_addrs, addr = (char *) vector_getentry (defaults->listen_addrs,
i, &size); i, &size);
vector_append(conf->listen_addrs, addr, size); vector_append (conf->listen_addrs, addr, size);
} }
} }
#ifdef FILTER_ENABLE #ifdef FILTER_ENABLE
if (defaults->filter) { if (defaults->filter) {
conf->filter = safestrdup (defaults->filter); conf->filter = safestrdup (defaults->filter);
@ -495,7 +491,7 @@ static void initialize_with_defaults (struct config_s *conf,
conf->filter_url = defaults->filter_url; conf->filter_url = defaults->filter_url;
conf->filter_extended = defaults->filter_extended; conf->filter_extended = defaults->filter_extended;
conf->filter_casesensitive = defaults->filter_casesensitive; conf->filter_casesensitive = defaults->filter_casesensitive;
#endif /* FILTER_ENABLE */ #endif /* FILTER_ENABLE */
#ifdef XTINYPROXY_ENABLE #ifdef XTINYPROXY_ENABLE
conf->add_xtinyproxy = defaults->add_xtinyproxy; conf->add_xtinyproxy = defaults->add_xtinyproxy;
@ -513,7 +509,7 @@ static void initialize_with_defaults (struct config_s *conf,
#ifdef UPSTREAM_SUPPORT #ifdef UPSTREAM_SUPPORT
/* struct upstream *upstream_list; */ /* struct upstream *upstream_list; */
#endif /* UPSTREAM_SUPPORT */ #endif /* UPSTREAM_SUPPORT */
if (defaults->pidpath) { if (defaults->pidpath) {
conf->pidpath = safestrdup (defaults->pidpath); conf->pidpath = safestrdup (defaults->pidpath);
@ -521,6 +517,10 @@ static void initialize_with_defaults (struct config_s *conf,
conf->idletimeout = defaults->idletimeout; conf->idletimeout = defaults->idletimeout;
#ifdef UPSTREAM_SUPPORT
conf->deadtime = defaults->deadtime;
#endif
if (defaults->bind_address) { if (defaults->bind_address) {
conf->bind_address = safestrdup (defaults->bind_address); conf->bind_address = safestrdup (defaults->bind_address);
} }
@ -589,6 +589,15 @@ int reload_config_file (const char *config_fname, struct config_s *conf,
MAX_IDLE_TIME); MAX_IDLE_TIME);
conf->idletimeout = MAX_IDLE_TIME; conf->idletimeout = MAX_IDLE_TIME;
} }
#ifdef UPSTREAM_SUPPORT
if (conf->deadtime == 0) {
log_message (LOG_WARNING, "Invalid dead time setting. "
"Only values greater than zero are allowed. "
"Therefore setting idle timeout to %u seconds.",
MAX_DEAD_TIME);
conf->deadtime = MAX_DEAD_TIME;
}
#endif
done: done:
return ret; return ret;
@ -659,8 +668,7 @@ set_bool_arg (unsigned int *var, const char *line, regmatch_t * match)
return 0; return 0;
} }
static unsigned long static unsigned long get_long_arg (const char *line, regmatch_t * match)
get_long_arg (const char *line, regmatch_t * match)
{ {
assert (line); assert (line);
assert (match && match->rm_so != -1); assert (match && match->rm_so != -1);
@ -668,8 +676,7 @@ get_long_arg (const char *line, regmatch_t * match)
return strtoul (line + match->rm_so, NULL, 0); return strtoul (line + match->rm_so, NULL, 0);
} }
static int static int set_int_arg (unsigned int *var, const char *line, regmatch_t * match)
set_int_arg (unsigned int *var, const char *line, regmatch_t * match)
{ {
assert (var); assert (var);
assert (line); assert (line);
@ -726,8 +733,7 @@ static HANDLE_FUNC (handle_viaproxyname)
if (r) if (r)
return r; return r;
log_message (LOG_INFO, log_message (LOG_INFO,
"Setting \"Via\" header to '%s'", "Setting \"Via\" header to '%s'", conf->via_proxy_name);
conf->via_proxy_name);
return 0; return 0;
} }
@ -739,8 +745,7 @@ static HANDLE_FUNC (handle_disableviaheader)
return r; return r;
} }
log_message (LOG_INFO, log_message (LOG_INFO, "Disabling transmission of the \"Via\" header.");
"Disabling transmission of the \"Via\" header.");
return 0; return 0;
} }
@ -811,15 +816,13 @@ static HANDLE_FUNC (handle_maxclients)
static HANDLE_FUNC (handle_maxspareservers) static HANDLE_FUNC (handle_maxspareservers)
{ {
child_configure (CHILD_MAXSPARESERVERS, child_configure (CHILD_MAXSPARESERVERS, get_long_arg (line, &match[2]));
get_long_arg (line, &match[2]));
return 0; return 0;
} }
static HANDLE_FUNC (handle_minspareservers) static HANDLE_FUNC (handle_minspareservers)
{ {
child_configure (CHILD_MINSPARESERVERS, child_configure (CHILD_MINSPARESERVERS, get_long_arg (line, &match[2]));
get_long_arg (line, &match[2]));
return 0; return 0;
} }
@ -841,6 +844,13 @@ static HANDLE_FUNC (handle_timeout)
return set_int_arg (&conf->idletimeout, line, &match[2]); return set_int_arg (&conf->idletimeout, line, &match[2]);
} }
#ifdef UPSTREAM_SUPPORT
static HANDLE_FUNC (handle_deadtime)
{
return set_int_arg (&conf->deadtime, line, &match[2]);
}
#endif
static HANDLE_FUNC (handle_connectport) static HANDLE_FUNC (handle_connectport)
{ {
add_connect_port_allowed (get_long_arg (line, &match[2]), add_connect_port_allowed (get_long_arg (line, &match[2]),
@ -896,18 +906,18 @@ static HANDLE_FUNC (handle_listen)
} }
if (conf->listen_addrs == NULL) { if (conf->listen_addrs == NULL) {
conf->listen_addrs = vector_create(); conf->listen_addrs = vector_create ();
if (conf->listen_addrs == NULL) { if (conf->listen_addrs == NULL) {
log_message(LOG_WARNING, "Could not create a list " log_message (LOG_WARNING, "Could not create a list "
"of listen addresses."); "of listen addresses.");
safefree(arg); safefree (arg);
return -1; return -1;
} }
} }
vector_append (conf->listen_addrs, arg, strlen(arg) + 1); vector_append (conf->listen_addrs, arg, strlen (arg) + 1);
log_message(LOG_INFO, "Added address [%s] to listen addresses.", arg); log_message (LOG_INFO, "Added address [%s] to listen addresses.", arg);
safefree (arg); safefree (arg);
return 0; return 0;
@ -994,10 +1004,10 @@ static HANDLE_FUNC (handle_loglevel)
static HANDLE_FUNC (handle_basicauth) static HANDLE_FUNC (handle_basicauth)
{ {
char *user, *pass; char *user, *pass;
user = get_string_arg(line, &match[2]); user = get_string_arg (line, &match[2]);
if (!user) if (!user)
return -1; return -1;
pass = get_string_arg(line, &match[3]); pass = get_string_arg (line, &match[3]);
if (!pass) { if (!pass) {
safefree (user); safefree (user);
return -1; return -1;
@ -1089,58 +1099,90 @@ static HANDLE_FUNC (handle_reversepath)
#ifdef UPSTREAM_SUPPORT #ifdef UPSTREAM_SUPPORT
static enum proxy_type pt_from_string(const char *s) static enum proxy_type pt_from_string (const char *s)
{ {
static const char pt_map[][7] = { static const char pt_map[][7] = {
[PT_NONE] = "none", [PT_NONE] = "none",
[PT_HTTP] = "http", [PT_HTTP] = "http",
[PT_SOCKS4] = "socks4", [PT_SOCKS4] = "socks4",
[PT_SOCKS5] = "socks5", [PT_SOCKS5] = "socks5",
}; };
unsigned i; unsigned i;
for (i = 0; i < sizeof(pt_map)/sizeof(pt_map[0]); i++) for (i = 0; i < sizeof (pt_map) / sizeof (pt_map[0]); i++)
if (!strcmp(pt_map[i], s)) if (!strcmp (pt_map[i], s))
return i; return i;
return PT_NONE; return PT_NONE;
} }
static HANDLE_FUNC (handle_upstream) static HANDLE_FUNC (handle_upstream)
{ {
char *ip; struct upstream_proxy_list *pltr, *plist;
int port, mi = 2; int mi = 2;
char *domain = 0, *user = 0, *pass = 0, *tmp; char *domain = 0, *user = 0, *pass = 0, *tmp;
enum proxy_type pt; enum proxy_type pt;
pltr = plist = (upstream_proxy_list_t *)
safemalloc (sizeof (upstream_proxy_list_t));
tmp = get_string_arg (line, &match[mi]); tmp = get_string_arg (line, &match[mi]);
pt = pt_from_string(tmp); pt = pt_from_string (tmp);
safefree(tmp); safefree (tmp);
mi += 2; mi += 2;
if (match[mi].rm_so != -1) if (match[mi].rm_so != -1)
user = get_string_arg (line, &match[mi]); user = get_string_arg (line, &match[mi]);
mi++; mi++;
if (match[mi].rm_so != -1) if (match[mi].rm_so != -1)
pass = get_string_arg (line, &match[mi]); pass = get_string_arg (line, &match[mi]);
mi++; mi++;
plist->host = get_string_arg (line, &match[mi]);
ip = get_string_arg (line, &match[mi]); if (!plist->host)
if (!ip)
return -1; return -1;
mi += 5; mi += 5;
plist->port = (int) get_long_arg (line, &match[mi]);
plist->last_failed_connect = (time_t) 0;
port = (int) get_long_arg (line, &match[mi]); mi += 2;
mi += 3; /* if != -1 we have a list of proxy hosts seperated by |. */
if (match[mi].rm_so != -1) {
/* loop over proxy host list */
char *phl, *pptr;
phl = get_string_arg (line, &match[mi]);
if (!phl)
return -1;
pptr = strtok (phl, "|");
while (pptr) {
char *cptr;
plist->next = (upstream_proxy_list_t *)
safemalloc (sizeof (upstream_proxy_list_t));
plist = plist->next;
cptr = strchr (pptr, ':');
*cptr++ = '\0';
plist->host = strdup (pptr);
plist->port = strtoul (cptr, NULL, 0);
plist->last_failed_connect = (time_t) 0;
pptr = strtok (NULL, "|");
}
safefree (phl);
}
mi += 10;
if (match[mi].rm_so != -1) if (match[mi].rm_so != -1)
domain = get_string_arg (line, &match[mi]); domain = get_string_arg (line, &match[mi]);
upstream_add (ip, port, domain, user, pass, pt, &conf->upstream_list); upstream_add (pltr, domain, user, pass, pt, &conf->upstream_list);
safefree (user); safefree (user);
safefree (pass); safefree (pass);
safefree (domain); safefree (domain);
safefree (ip); while (pltr) {
struct upstream_proxy_list *tmpp = pltr;
pltr = pltr->next;
safefree (tmpp->host);
safefree (tmpp);
}
return 0; return 0;
} }
@ -1153,7 +1195,7 @@ static HANDLE_FUNC (handle_upstream_no)
if (!domain) if (!domain)
return -1; return -1;
upstream_add (NULL, 0, domain, 0, 0, PT_NONE, &conf->upstream_list); upstream_add (NULL, domain, 0, 0, PT_NONE, &conf->upstream_list);
safefree (domain); safefree (domain);
return 0; return 0;

View File

@ -55,7 +55,7 @@ struct config_s {
unsigned int filter_casesensitive; /* boolean */ unsigned int filter_casesensitive; /* boolean */
#endif /* FILTER_ENABLE */ #endif /* FILTER_ENABLE */
#ifdef XTINYPROXY_ENABLE #ifdef XTINYPROXY_ENABLE
unsigned int add_xtinyproxy; /* boolean */ unsigned int add_xtinyproxy; /* boolean */
#endif #endif
#ifdef REVERSE_SUPPORT #ifdef REVERSE_SUPPORT
struct reversepath *reversepath_list; struct reversepath *reversepath_list;
@ -68,6 +68,9 @@ struct config_s {
#endif /* UPSTREAM_SUPPORT */ #endif /* UPSTREAM_SUPPORT */
char *pidpath; char *pidpath;
unsigned int idletimeout; unsigned int idletimeout;
#ifdef UPSTREAM_SUPPORT
unsigned int deadtime;
#endif /* UPSTREAM_SUPPORT */
char *bind_address; char *bind_address;
unsigned int bindsame; unsigned int bindsame;
@ -116,6 +119,8 @@ struct config_s {
extern int reload_config_file (const char *config_fname, struct config_s *conf, extern int reload_config_file (const char *config_fname, struct config_s *conf,
struct config_s *defaults); struct config_s *defaults);
extern void free_config (struct config_s *conf);
int config_compile_regex (void); int config_compile_regex (void);
#endif #endif

View File

@ -25,7 +25,7 @@
* Now, this routine adds a "port" to the list. It also creates the list if * Now, this routine adds a "port" to the list. It also creates the list if
* it hasn't already by done. * it hasn't already by done.
*/ */
void add_connect_port_allowed (int port, vector_t *connect_ports) void add_connect_port_allowed (int port, vector_t * connect_ports)
{ {
if (!*connect_ports) { if (!*connect_ports) {
*connect_ports = vector_create (); *connect_ports = vector_create ();
@ -53,8 +53,8 @@ int check_allowed_connect_ports (int port, vector_t connect_ports)
int *data; int *data;
/* /*
* The absence of ConnectPort options in the config file * The absence of ConnectPort options in the config file
* meanas that all ports are allowed for CONNECT. * meanas that all ports are allowed for CONNECT.
*/ */
if (!connect_ports) if (!connect_ports)
return 1; return 1;

View File

@ -24,7 +24,7 @@
#include "common.h" #include "common.h"
#include "vector.h" #include "vector.h"
extern void add_connect_port_allowed (int port, vector_t *connect_ports); extern void add_connect_port_allowed (int port, vector_t * connect_ports);
int check_allowed_connect_ports (int port, vector_t connect_ports); int check_allowed_connect_ports (int port, vector_t connect_ports);
void free_connect_ports_list (vector_t connect_ports); void free_connect_ports_list (vector_t connect_ports);

View File

@ -41,10 +41,9 @@ void makedaemon (void)
if (fork () != 0) if (fork () != 0)
exit (0); exit (0);
if (chdir ("/") != 0) { if (chdir ("/") != 0) {
log_message (LOG_WARNING, log_message (LOG_WARNING, "Could not change directory to /");
"Could not change directory to /"); }
}
umask (0177); umask (0177);

View File

@ -104,13 +104,11 @@ void filter_init (void)
if (*s == '\0') if (*s == '\0')
continue; continue;
if (!p) /* head of list */ if (!p) /* head of list */
fl = p = fl = p = (struct filter_list *)
(struct filter_list *)
safecalloc (1, sizeof (struct filter_list)); safecalloc (1, sizeof (struct filter_list));
else { /* next entry */ else { /* next entry */
p->next = p->next = (struct filter_list *)
(struct filter_list *)
safecalloc (1, sizeof (struct filter_list)); safecalloc (1, sizeof (struct filter_list));
p = p->next; p = p->next;
} }

View File

@ -104,7 +104,7 @@ hashmap_t hashmap_create (unsigned int nbuckets)
if (!ptr) if (!ptr)
return NULL; return NULL;
ptr->seed = (uint32_t)rand(); ptr->seed = (uint32_t) rand ();
ptr->size = nbuckets; ptr->size = nbuckets;
ptr->buckets = (struct hashbucket_s *) safecalloc (nbuckets, ptr->buckets = (struct hashbucket_s *) safecalloc (nbuckets,
sizeof (struct sizeof (struct
@ -508,8 +508,7 @@ char *lookup_variable (hashmap_t map, const char *varname)
if (hashmap_is_end (map, result_iter)) if (hashmap_is_end (map, result_iter))
return (NULL); return (NULL);
if (hashmap_return_entry (map, result_iter, if (hashmap_return_entry (map, result_iter, &key, (void **) &data) < 0)
&key, (void **) &data) < 0)
return (NULL); return (NULL);
return (data); return (data);

View File

@ -36,19 +36,19 @@ extern void *debugging_realloc (void *ptr, size_t size, const char *file,
extern char *debugging_strdup (const char *s, const char *file, extern char *debugging_strdup (const char *s, const char *file,
unsigned long line); unsigned long line);
# define safecalloc(x, y) debugging_calloc(x, y, __FILE__, __LINE__) #define safecalloc(x, y) debugging_calloc(x, y, __FILE__, __LINE__)
# define safemalloc(x) debugging_malloc(x, __FILE__, __LINE__) #define safemalloc(x) debugging_malloc(x, __FILE__, __LINE__)
# define saferealloc(x, y) debugging_realloc(x, y, __FILE__, __LINE__) #define saferealloc(x, y) debugging_realloc(x, y, __FILE__, __LINE__)
# define safestrdup(x) debugging_strdup(x, __FILE__, __LINE__) #define safestrdup(x) debugging_strdup(x, __FILE__, __LINE__)
# define safefree(x) (debugging_free(x, __FILE__, __LINE__), *(&(x)) = NULL) #define safefree(x) (debugging_free(x, __FILE__, __LINE__), *(&(x)) = NULL)
#else #else
# define safecalloc(x, y) calloc(x, y) #define safecalloc(x, y) calloc(x, y)
# define safemalloc(x) malloc(x) #define safemalloc(x) malloc(x)
# define saferealloc(x, y) realloc(x, y) #define saferealloc(x, y) realloc(x, y)
# define safefree(x) (free (x), *(&(x)) = NULL) #define safefree(x) (free (x), *(&(x)) = NULL)
# define safestrdup(x) strdup(x) #define safestrdup(x) strdup(x)
#endif #endif

View File

@ -86,8 +86,7 @@ static char *get_html_file (unsigned int errornum)
/* /*
* Send an already-opened file to the client with variable substitution. * Send an already-opened file to the client with variable substitution.
*/ */
int int send_html_file (FILE * infile, struct conn_s *connptr)
send_html_file (FILE *infile, struct conn_s *connptr)
{ {
char *inbuf; char *inbuf;
char *varstart = NULL; char *varstart = NULL;
@ -105,8 +104,9 @@ send_html_file (FILE *infile, struct conn_s *connptr)
if (in_variable) { if (in_variable) {
*p = '\0'; *p = '\0';
varval = (const char *) varval = (const char *)
lookup_variable (connptr->error_variables, lookup_variable
varstart); (connptr->error_variables,
varstart);
if (!varval) if (!varval)
varval = "(unknown)"; varval = "(unknown)";
r = write_message (connptr->client_fd, r = write_message (connptr->client_fd,
@ -160,25 +160,21 @@ int send_http_headers (struct conn_s *connptr, int code, const char *message)
const char headers[] = const char headers[] =
"HTTP/1.0 %d %s\r\n" "HTTP/1.0 %d %s\r\n"
"Server: %s/%s\r\n" "Server: %s/%s\r\n"
"Content-Type: text/html\r\n" "Content-Type: text/html\r\n" "%s" "Connection: close\r\n" "\r\n";
"%s"
"Connection: close\r\n" "\r\n";
const char p_auth_str[] = const char p_auth_str[] =
"Proxy-Authenticate: Basic realm=\"" "Proxy-Authenticate: Basic realm=\"" PACKAGE_NAME "\"\r\n";
PACKAGE_NAME "\"\r\n";
const char w_auth_str[] = const char w_auth_str[] =
"WWW-Authenticate: Basic realm=\"" "WWW-Authenticate: Basic realm=\"" PACKAGE_NAME "\"\r\n";
PACKAGE_NAME "\"\r\n";
/* according to rfc7235, the 407 error must be accompanied by /* according to rfc7235, the 407 error must be accompanied by
a Proxy-Authenticate header field. */ * a Proxy-Authenticate header field. */
const char *add = code == 407 ? p_auth_str : (code == 401 ? w_auth_str : ""); const char *add =
code == 407 ? p_auth_str : (code == 401 ? w_auth_str : "");
return (write_message (connptr->client_fd, headers, return (write_message (connptr->client_fd, headers,
code, message, PACKAGE, VERSION, code, message, PACKAGE, VERSION, add));
add));
} }
/* /*
@ -207,12 +203,12 @@ int send_http_error_message (struct conn_s *connptr)
error_file = get_html_file (connptr->error_number); error_file = get_html_file (connptr->error_number);
if (!(infile = fopen (error_file, "r"))) { if (!(infile = fopen (error_file, "r"))) {
char *detail = lookup_variable (connptr->error_variables, "detail"); char *detail =
return (write_message (connptr->client_fd, fallback_error, lookup_variable (connptr->error_variables, "detail");
connptr->error_number, return (write_message
connptr->error_string, (connptr->client_fd, fallback_error,
connptr->error_string, connptr->error_number, connptr->error_string,
detail, PACKAGE, VERSION)); connptr->error_string, detail, PACKAGE, VERSION));
} }
ret = send_html_file (infile, connptr); ret = send_html_file (infile, connptr);
@ -274,8 +270,7 @@ int add_standard_vars (struct conn_s *connptr)
gmtime (&global_time)); gmtime (&global_time));
add_error_variable (connptr, "date", timebuf); add_error_variable (connptr, "date", timebuf);
add_error_variable (connptr, "website", add_error_variable (connptr, "website", "https://tinyproxy.github.io/");
"https://tinyproxy.github.io/");
add_error_variable (connptr, "version", VERSION); add_error_variable (connptr, "version", VERSION);
add_error_variable (connptr, "package", PACKAGE); add_error_variable (connptr, "package", PACKAGE);

View File

@ -63,7 +63,7 @@ static int log_level = LOG_INFO;
*/ */
static vector_t log_message_storage; static vector_t log_message_storage;
static unsigned int logging_initialized = FALSE; /* boolean */ static unsigned int logging_initialized = FALSE; /* boolean */
/* /*
* Open the log file and store the file descriptor in a global location. * Open the log file and store the file descriptor in a global location.
@ -71,8 +71,8 @@ static unsigned int logging_initialized = FALSE; /* boolean */
int open_log_file (const char *log_file_name) int open_log_file (const char *log_file_name)
{ {
if (log_file_name == NULL) { if (log_file_name == NULL) {
if(config.godaemon == FALSE) if (config.godaemon == FALSE)
log_file_fd = fileno(stdout); log_file_fd = fileno (stdout);
else else
log_file_fd = -1; log_file_fd = -1;
} else { } else {
@ -86,7 +86,7 @@ int open_log_file (const char *log_file_name)
*/ */
void close_log_file (void) void close_log_file (void)
{ {
if (log_file_fd < 0 || log_file_fd == fileno(stdout)) { if (log_file_fd < 0 || log_file_fd == fileno (stdout)) {
return; return;
} }
@ -161,7 +161,7 @@ void log_message (int level, const char *fmt, ...)
goto out; goto out;
} }
if(!config.syslog && log_file_fd == -1) if (!config.syslog && log_file_fd == -1)
goto out; goto out;
if (config.syslog) { if (config.syslog) {
@ -187,12 +187,12 @@ void log_message (int level, const char *fmt, ...)
* Overwrite the '\0' and leave room for a trailing '\n' * Overwrite the '\0' and leave room for a trailing '\n'
* be added next. * be added next.
*/ */
p = str + strlen(str); p = str + strlen (str);
vsnprintf (p, STRING_LENGTH - strlen(str) - 1, fmt, args); vsnprintf (p, STRING_LENGTH - strlen (str) - 1, fmt, args);
p = str + strlen(str); p = str + strlen (str);
*p = '\n'; *p = '\n';
*(p+1) = '\0'; *(p + 1) = '\0';
assert (log_file_fd >= 0); assert (log_file_fd >= 0);
@ -200,11 +200,11 @@ void log_message (int level, const char *fmt, ...)
if (ret == -1) { if (ret == -1) {
config.syslog = TRUE; config.syslog = TRUE;
log_message(LOG_CRIT, "ERROR: Could not write to log " log_message (LOG_CRIT, "ERROR: Could not write to log "
"file %s: %s.", "file %s: %s.",
config.logf_name, strerror(errno)); config.logf_name, strerror (errno));
log_message(LOG_CRIT, log_message (LOG_CRIT,
"Falling back to syslog logging"); "Falling back to syslog logging");
} }
fsync (log_file_fd); fsync (log_file_fd);
@ -227,7 +227,7 @@ static void send_stored_logs (void)
if (log_message_storage == NULL) if (log_message_storage == NULL)
return; return;
log_message(LOG_DEBUG, "sending stored logs"); log_message (LOG_DEBUG, "sending stored logs");
for (i = 0; (ssize_t) i != vector_length (log_message_storage); ++i) { for (i = 0; (ssize_t) i != vector_length (log_message_storage); ++i) {
string = string =
@ -252,7 +252,7 @@ static void send_stored_logs (void)
vector_delete (log_message_storage); vector_delete (log_message_storage);
log_message_storage = NULL; log_message_storage = NULL;
log_message(LOG_DEBUG, "done sending stored logs"); log_message (LOG_DEBUG, "done sending stored logs");
} }
/** /**

View File

@ -24,7 +24,7 @@
#define TINYPROXY_LOG_H #define TINYPROXY_LOG_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include <config.h> #include <config.h>
#endif #endif
/* /*
@ -92,13 +92,13 @@
* DEBUG2("There was a big problem: %s in connptr %p", "hello", connptr); * DEBUG2("There was a big problem: %s in connptr %p", "hello", connptr);
*/ */
#ifndef NDEBUG #ifndef NDEBUG
# define DEBUG1(x) \ #define DEBUG1(x) \
log_message(LOG_DEBUG, "[%s:%d] " x, __FILE__, __LINE__) log_message(LOG_DEBUG, "[%s:%d] " x, __FILE__, __LINE__)
# define DEBUG2(x, y...) \ #define DEBUG2(x, y...) \
log_message(LOG_DEBUG, "[%s:%d] " x, __FILE__, __LINE__, ## y) log_message(LOG_DEBUG, "[%s:%d] " x, __FILE__, __LINE__, ## y)
#else #else
# define DEBUG1(x) do { } while(0) #define DEBUG1(x) do { } while(0)
# define DEBUG2(x, y...) do { } while(0) #define DEBUG2(x, y...) do { } while(0)
#endif #endif
extern int open_log_file (const char *file); extern int open_log_file (const char *file);

View File

@ -54,8 +54,7 @@ unsigned int received_sighup = FALSE; /* boolean */
/* /*
* Handle a signal * Handle a signal
*/ */
static void static void takesig (int sig)
takesig (int sig)
{ {
pid_t pid; pid_t pid;
int status; int status;
@ -80,8 +79,7 @@ takesig (int sig)
/* /*
* Display the version information for the user. * Display the version information for the user.
*/ */
static void static void display_version (void)
display_version (void)
{ {
printf ("%s %s\n", PACKAGE, VERSION); printf ("%s %s\n", PACKAGE, VERSION);
} }
@ -89,8 +87,7 @@ display_version (void)
/* /*
* Display usage to the user. * Display usage to the user.
*/ */
static void static void display_usage (void)
display_usage (void)
{ {
int features = 0; int features = 0;
@ -143,8 +140,7 @@ display_usage (void)
"<https://tinyproxy.github.io/>.\n"); "<https://tinyproxy.github.io/>.\n");
} }
static int static int get_id (char *str)
get_id (char *str)
{ {
char *tstr; char *tstr;
@ -168,8 +164,7 @@ get_id (char *str)
* *
* This function parses command line arguments. * This function parses command line arguments.
**/ **/
static void static void process_cmdline (int argc, char **argv, struct config_s *conf)
process_cmdline (int argc, char **argv, struct config_s *conf)
{ {
int opt; int opt;
@ -215,8 +210,7 @@ process_cmdline (int argc, char **argv, struct config_s *conf)
* the config file. This function is typically called during * the config file. This function is typically called during
* initialization when the effective user is root. * initialization when the effective user is root.
**/ **/
static void static void change_user (const char *program)
change_user (const char *program)
{ {
if (config.group && strlen (config.group) > 0) { if (config.group && strlen (config.group) > 0) {
int gid = get_id (config.group); int gid = get_id (config.group);
@ -240,7 +234,6 @@ change_user (const char *program)
program, config.group); program, config.group);
exit (EX_NOPERM); exit (EX_NOPERM);
} }
#ifdef HAVE_SETGROUPS #ifdef HAVE_SETGROUPS
/* Drop all supplementary groups, otherwise these are inherited from the calling process */ /* Drop all supplementary groups, otherwise these are inherited from the calling process */
if (setgroups (0, NULL) < 0) { if (setgroups (0, NULL) < 0) {
@ -285,7 +278,7 @@ change_user (const char *program)
static void initialize_config_defaults (struct config_s *conf) static void initialize_config_defaults (struct config_s *conf)
{ {
memset (conf, 0, sizeof(*conf)); memset (conf, 0, sizeof (*conf));
conf->config_file = safestrdup (SYSCONFDIR "/tinyproxy.conf"); conf->config_file = safestrdup (SYSCONFDIR "/tinyproxy.conf");
if (!conf->config_file) { if (!conf->config_file) {
@ -300,6 +293,9 @@ static void initialize_config_defaults (struct config_s *conf)
conf->errorpages = NULL; conf->errorpages = NULL;
conf->stathost = safestrdup (TINYPROXY_STATHOST); conf->stathost = safestrdup (TINYPROXY_STATHOST);
conf->idletimeout = MAX_IDLE_TIME; conf->idletimeout = MAX_IDLE_TIME;
#ifdef UPSTREAM_SUPPORT
conf->deadtime = MAX_DEAD_TIME;
#endif
conf->logf_name = NULL; conf->logf_name = NULL;
conf->pidpath = NULL; conf->pidpath = NULL;
} }
@ -326,8 +322,7 @@ done:
return ret; return ret;
} }
int int main (int argc, char **argv)
main (int argc, char **argv)
{ {
/* Only allow u+rw bits. This may be required for some versions /* Only allow u+rw bits. This may be required for some versions
* of glibc so that mkstemp() doesn't make us vulnerable. * of glibc so that mkstemp() doesn't make us vulnerable.
@ -336,7 +331,7 @@ main (int argc, char **argv)
log_message (LOG_INFO, "Initializing " PACKAGE " ..."); log_message (LOG_INFO, "Initializing " PACKAGE " ...");
if (config_compile_regex()) { if (config_compile_regex ()) {
exit (EX_SOFTWARE); exit (EX_SOFTWARE);
} }
@ -344,8 +339,7 @@ main (int argc, char **argv)
process_cmdline (argc, argv, &config_defaults); process_cmdline (argc, argv, &config_defaults);
if (reload_config_file (config_defaults.config_file, if (reload_config_file (config_defaults.config_file,
&config, &config, &config_defaults)) {
&config_defaults)) {
exit (EX_SOFTWARE); exit (EX_SOFTWARE);
} }
@ -362,8 +356,8 @@ main (int argc, char **argv)
if (config.godaemon == TRUE) { if (config.godaemon == TRUE) {
if (!config.syslog && config.logf_name == NULL) if (!config.syslog && config.logf_name == NULL)
fprintf(stderr, "WARNING: logging deactivated " fprintf (stderr, "WARNING: logging deactivated "
"(can't log to stdout when daemonized)\n"); "(can't log to stdout when daemonized)\n");
makedaemon (); makedaemon ();
} }
@ -373,14 +367,13 @@ main (int argc, char **argv)
argv[0]); argv[0]);
exit (EX_OSERR); exit (EX_OSERR);
} }
#ifdef FILTER_ENABLE #ifdef FILTER_ENABLE
if (config.filter) if (config.filter)
filter_init (); filter_init ();
#endif /* FILTER_ENABLE */ #endif /* FILTER_ENABLE */
/* Start listening on the selected port. */ /* Start listening on the selected port. */
if (child_listening_sockets(config.listen_addrs, config.port) < 0) { if (child_listening_sockets (config.listen_addrs, config.port) < 0) {
fprintf (stderr, "%s: Could not create listening sockets.\n", fprintf (stderr, "%s: Could not create listening sockets.\n",
argv[0]); argv[0]);
exit (EX_OSERR); exit (EX_OSERR);
@ -451,12 +444,13 @@ main (int argc, char **argv)
"Could not remove PID file \"%s\": %s.", "Could not remove PID file \"%s\": %s.",
config.pidpath, strerror (errno)); config.pidpath, strerror (errno));
} }
#ifdef FILTER_ENABLE #ifdef FILTER_ENABLE
if (config.filter) if (config.filter)
filter_destroy (); filter_destroy ();
#endif /* FILTER_ENABLE */ #endif /* FILTER_ENABLE */
free_config (&config);
shutdown_logging (); shutdown_logging ();
return EXIT_SUCCESS; return EXIT_SUCCESS;

View File

@ -27,6 +27,9 @@
/* Global variables for the main controls of the program */ /* Global variables for the main controls of the program */
#define MAXBUFFSIZE ((size_t)(1024 * 96)) /* Max size of buffer */ #define MAXBUFFSIZE ((size_t)(1024 * 96)) /* Max size of buffer */
#define MAX_IDLE_TIME (60 * 10) /* 10 minutes of no activity */ #define MAX_IDLE_TIME (60 * 10) /* 10 minutes of no activity */
#ifdef UPSTREAM_SUPPORT
#define MAX_DEAD_TIME (60 * 10) /* 10 minutes of no activity */
#endif
/* Global Structures used in the program */ /* Global Structures used in the program */
extern struct config_s config; extern struct config_s config;

View File

@ -36,7 +36,7 @@ ssize_t safe_write (int fd, const void *buf, size_t count)
{ {
ssize_t len; ssize_t len;
size_t bytestosend; size_t bytestosend;
const char *buffer = buf; const char *buffer = buf;
assert (fd >= 0); assert (fd >= 0);
assert (buffer != NULL); assert (buffer != NULL);
@ -204,8 +204,7 @@ ssize_t readline (int fd, char **whole_buffer)
break; break;
} }
line_ptr->next = line_ptr->next = (struct read_lines_s *)
(struct read_lines_s *)
safecalloc (sizeof (struct read_lines_s), 1); safecalloc (sizeof (struct read_lines_s), 1);
if (!line_ptr->next) { if (!line_ptr->next) {
ret = -ENOMEM; ret = -ENOMEM;

View File

@ -1417,12 +1417,13 @@ connect_to_upstream (struct conn_s *connptr, struct request_s *request)
*/ */
return -1; return -1;
#else #else
struct upstream_proxy_list *upp;
char *combined_string; char *combined_string;
int len; int len;
struct upstream *cur_upstream = connptr->upstream_proxy; struct upstream *cur_upstream = connptr->upstream_proxy;
if (!cur_upstream) { if (!cur_upstream || !cur_upstream->plist) {
log_message (LOG_WARNING, log_message (LOG_WARNING,
"No upstream proxy defined for %s.", "No upstream proxy defined for %s.",
request->host); request->host);
@ -1431,11 +1432,39 @@ connect_to_upstream (struct conn_s *connptr, struct request_s *request)
return -1; return -1;
} }
connptr->server_fd = upp = cur_upstream->plist;
opensock (cur_upstream->host, cur_upstream->port, while (upp) {
connptr->server_ip_addr); double tdiff;
if (upp->last_failed_connect > 0) {
tdiff =
difftime (time (NULL), upp->last_failed_connect);
if (tdiff < config.deadtime) {
log_message (LOG_INFO,
"Won't try to connect to upstream "
"proxy %s:%d during dead time.",
upp->host, upp->port);
upp = upp->next;
continue;
} else {
upp->last_failed_connect = (time_t) 0;
}
}
connptr->server_fd =
opensock (upp->host, upp->port, connptr->server_ip_addr);
if (connptr->server_fd < 0) { if (connptr->server_fd < 0) {
log_message (LOG_WARNING,
"Could not connect to upstream proxy. "
"Try next in list if available.");
upp->last_failed_connect = time (NULL);
} else {
cur_upstream->host = upp->host;
cur_upstream->port = upp->port;
break;
}
upp = upp->next;
}
if (!upp || connptr->server_fd < 0) {
log_message (LOG_WARNING, log_message (LOG_WARNING,
"Could not connect to upstream proxy."); "Could not connect to upstream proxy.");
indicate_http_error (connptr, 404, indicate_http_error (connptr, 404,

View File

@ -139,13 +139,10 @@ char *reverse_rewrite_url (struct conn_s *connptr, hashmap_t hashofheaders,
&& (reverse = && (reverse =
reversepath_get (cookieval + reversepath_get (cookieval +
strlen (REVERSE_COOKIE) + 1, strlen (REVERSE_COOKIE) + 1,
config.reversepath_list))) config.reversepath_list))) {
{
rewrite_url = (char *) safemalloc rewrite_url = (char *) safemalloc
(strlen (url) + (strlen (url) + strlen (reverse->url) + 1);
strlen (reverse->url) +
1);
strcpy (rewrite_url, reverse->url); strcpy (rewrite_url, reverse->url);
strcat (rewrite_url, url + 1); strcat (rewrite_url, url + 1);

View File

@ -37,7 +37,7 @@
/* /*
* Return a human readable error for getaddrinfo() and getnameinfo(). * Return a human readable error for getaddrinfo() and getnameinfo().
*/ */
static const char * get_gai_error (int n) static const char *get_gai_error (int n)
{ {
if (n == EAI_SYSTEM) if (n == EAI_SYSTEM)
return strerror (errno); return strerror (errno);
@ -50,8 +50,7 @@ static const char * get_gai_error (int n)
* returned if the bind succeeded. Otherwise, -1 is returned * returned if the bind succeeded. Otherwise, -1 is returned
* to indicate an error. * to indicate an error.
*/ */
static int static int bind_socket (int sockfd, const char *addr, int family)
bind_socket (int sockfd, const char *addr, int family)
{ {
struct addrinfo hints, *res, *ressave; struct addrinfo hints, *res, *ressave;
int n; int n;
@ -67,7 +66,8 @@ bind_socket (int sockfd, const char *addr, int family)
n = getaddrinfo (addr, NULL, &hints, &res); n = getaddrinfo (addr, NULL, &hints, &res);
if (n != 0) { if (n != 0) {
log_message (LOG_INFO, log_message (LOG_INFO,
"bind_socket: getaddrinfo failed for %s: ", addr, get_gai_error (n)); "bind_socket: getaddrinfo failed for %s: ", addr,
get_gai_error (n));
return -1; return -1;
} }
@ -100,8 +100,8 @@ int opensock (const char *host, int port, const char *bind_to)
assert (host != NULL); assert (host != NULL);
assert (port > 0); assert (port > 0);
log_message(LOG_INFO, log_message (LOG_INFO,
"opensock: opening connection to %s:%d", host, port); "opensock: opening connection to %s:%d", host, port);
memset (&hints, 0, sizeof (struct addrinfo)); memset (&hints, 0, sizeof (struct addrinfo));
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
@ -112,12 +112,13 @@ int opensock (const char *host, int port, const char *bind_to)
n = getaddrinfo (host, portstr, &hints, &res); n = getaddrinfo (host, portstr, &hints, &res);
if (n != 0) { if (n != 0) {
log_message (LOG_ERR, log_message (LOG_ERR,
"opensock: Could not retrieve address info for %s:%d: %s", host, port, get_gai_error (n)); "opensock: Could not retrieve address info for %s:%d: %s",
host, port, get_gai_error (n));
return -1; return -1;
} }
log_message(LOG_INFO, log_message (LOG_INFO,
"opensock: getaddrinfo returned for %s:%d", host, port); "opensock: getaddrinfo returned for %s:%d", host, port);
ressave = res; ressave = res;
do { do {
@ -128,8 +129,7 @@ int opensock (const char *host, int port, const char *bind_to)
/* Bind to the specified address */ /* Bind to the specified address */
if (bind_to) { if (bind_to) {
if (bind_socket (sockfd, bind_to, if (bind_socket (sockfd, bind_to, res->ai_family) < 0) {
res->ai_family) < 0) {
close (sockfd); close (sockfd);
continue; /* can't bind, so try again */ continue; /* can't bind, so try again */
} }
@ -151,8 +151,7 @@ int opensock (const char *host, int port, const char *bind_to)
if (res == NULL) { if (res == NULL) {
log_message (LOG_ERR, log_message (LOG_ERR,
"opensock: Could not establish a connection to %s:%d", "opensock: Could not establish a connection to %s:%d",
host, host, port);
port);
return -1; return -1;
} }
@ -185,14 +184,13 @@ int socket_blocking (int sock)
return fcntl (sock, F_SETFL, flags & ~O_NONBLOCK); return fcntl (sock, F_SETFL, flags & ~O_NONBLOCK);
} }
/** /**
* Try to listen on one socket based on the addrinfo * Try to listen on one socket based on the addrinfo
* as returned from getaddrinfo. * as returned from getaddrinfo.
* *
* Return the file descriptor upon success, -1 upon error. * Return the file descriptor upon success, -1 upon error.
*/ */
static int listen_on_one_socket(struct addrinfo *ad) static int listen_on_one_socket (struct addrinfo *ad)
{ {
int listenfd; int listenfd;
int ret; int ret;
@ -200,59 +198,60 @@ static int listen_on_one_socket(struct addrinfo *ad)
char numerichost[NI_MAXHOST]; char numerichost[NI_MAXHOST];
int flags = NI_NUMERICHOST; int flags = NI_NUMERICHOST;
ret = getnameinfo(ad->ai_addr, ad->ai_addrlen, ret = getnameinfo (ad->ai_addr, ad->ai_addrlen,
numerichost, NI_MAXHOST, NULL, 0, flags); numerichost, NI_MAXHOST, NULL, 0, flags);
if (ret != 0) { if (ret != 0) {
log_message(LOG_ERR, "getnameinfo failed: %s", get_gai_error (ret)); log_message (LOG_ERR, "getnameinfo failed: %s",
get_gai_error (ret));
return -1; return -1;
} }
log_message(LOG_INFO, "trying to listen on host[%s], family[%d], " log_message (LOG_INFO, "trying to listen on host[%s], family[%d], "
"socktype[%d], proto[%d]", numerichost, "socktype[%d], proto[%d]", numerichost,
ad->ai_family, ad->ai_socktype, ad->ai_protocol); ad->ai_family, ad->ai_socktype, ad->ai_protocol);
listenfd = socket(ad->ai_family, ad->ai_socktype, ad->ai_protocol); listenfd = socket (ad->ai_family, ad->ai_socktype, ad->ai_protocol);
if (listenfd == -1) { if (listenfd == -1) {
log_message(LOG_ERR, "socket() failed: %s", strerror(errno)); log_message (LOG_ERR, "socket() failed: %s", strerror (errno));
return -1; return -1;
} }
ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); ret = setsockopt (listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on));
if (ret != 0) { if (ret != 0) {
log_message(LOG_ERR, log_message (LOG_ERR,
"setsockopt failed to set SO_REUSEADDR: %s", "setsockopt failed to set SO_REUSEADDR: %s",
strerror(errno)); strerror (errno));
close(listenfd); close (listenfd);
return -1; return -1;
} }
if (ad->ai_family == AF_INET6) { if (ad->ai_family == AF_INET6) {
ret = setsockopt(listenfd, IPPROTO_IPV6, IPV6_V6ONLY, &on, ret = setsockopt (listenfd, IPPROTO_IPV6, IPV6_V6ONLY, &on,
sizeof(on)); sizeof (on));
if (ret != 0) { if (ret != 0) {
log_message(LOG_ERR, log_message (LOG_ERR,
"setsockopt failed to set IPV6_V6ONLY: %s", "setsockopt failed to set IPV6_V6ONLY: %s",
strerror(errno)); strerror (errno));
close(listenfd); close (listenfd);
return -1; return -1;
} }
} }
ret = bind(listenfd, ad->ai_addr, ad->ai_addrlen); ret = bind (listenfd, ad->ai_addr, ad->ai_addrlen);
if (ret != 0) { if (ret != 0) {
log_message(LOG_ERR, "bind failed: %s", strerror (errno)); log_message (LOG_ERR, "bind failed: %s", strerror (errno));
close(listenfd); close (listenfd);
return -1;
}
ret = listen(listenfd, MAXLISTEN);
if (ret != 0) {
log_message(LOG_ERR, "listen failed: %s", strerror(errno));
close(listenfd);
return -1; return -1;
} }
log_message(LOG_INFO, "listening on fd [%d]", listenfd); ret = listen (listenfd, MAXLISTEN);
if (ret != 0) {
log_message (LOG_ERR, "listen failed: %s", strerror (errno));
close (listenfd);
return -1;
}
log_message (LOG_INFO, "listening on fd [%d]", listenfd);
return listenfd; return listenfd;
} }
@ -277,8 +276,8 @@ int listen_sock (const char *addr, uint16_t port, vector_t listen_fds)
assert (port > 0); assert (port > 0);
assert (listen_fds != NULL); assert (listen_fds != NULL);
log_message(LOG_INFO, "listen_sock called with addr = '%s'", log_message (LOG_INFO, "listen_sock called with addr = '%s'",
addr == NULL ? "(NULL)" : addr); addr == NULL ? "(NULL)" : addr);
memset (&hints, 0, sizeof (struct addrinfo)); memset (&hints, 0, sizeof (struct addrinfo));
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
@ -291,21 +290,19 @@ int listen_sock (const char *addr, uint16_t port, vector_t listen_fds)
if (n != 0) { if (n != 0) {
log_message (LOG_ERR, log_message (LOG_ERR,
"Unable to getaddrinfo() for %s:%d because of %s", "Unable to getaddrinfo() for %s:%d because of %s",
addr, addr, port, get_gai_error (n));
port,
get_gai_error (n));
return -1; return -1;
} }
for (rp = result; rp != NULL; rp = rp->ai_next) { for (rp = result; rp != NULL; rp = rp->ai_next) {
int listenfd; int listenfd;
listenfd = listen_on_one_socket(rp); listenfd = listen_on_one_socket (rp);
if (listenfd == -1) { if (listenfd == -1) {
continue; continue;
} }
vector_append (listen_fds, &listenfd, sizeof(int)); vector_append (listen_fds, &listenfd, sizeof (int));
/* success */ /* success */
ret = 0; ret = 0;

View File

@ -59,8 +59,7 @@ void init_stats (void)
/* /*
* Display the statics of the tinyproxy server. * Display the statics of the tinyproxy server.
*/ */
int int showstats (struct conn_s *connptr)
showstats (struct conn_s *connptr)
{ {
char *message_buffer; char *message_buffer;
char opens[16], reqs[16], badconns[16], denied[16], refused[16]; char opens[16], reqs[16], badconns[16], denied[16], refused[16];
@ -78,32 +77,31 @@ showstats (struct conn_s *connptr)
return -1; return -1;
snprintf snprintf
(message_buffer, MAXBUFFSIZE, (message_buffer, MAXBUFFSIZE,
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" " "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" "
"\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n" "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
"<html>\n" "<html>\n"
"<head><title>%s version %s run-time statistics</title></head>\n" "<head><title>%s version %s run-time statistics</title></head>\n"
"<body>\n" "<body>\n"
"<h1>%s version %s run-time statistics</h1>\n" "<h1>%s version %s run-time statistics</h1>\n"
"<p>\n" "<p>\n"
"Number of open connections: %lu<br />\n" "Number of open connections: %lu<br />\n"
"Number of requests: %lu<br />\n" "Number of requests: %lu<br />\n"
"Number of bad connections: %lu<br />\n" "Number of bad connections: %lu<br />\n"
"Number of denied connections: %lu<br />\n" "Number of denied connections: %lu<br />\n"
"Number of refused connections due to high load: %lu\n" "Number of refused connections due to high load: %lu\n"
"</p>\n" "</p>\n"
"<hr />\n" "<hr />\n"
"<p><em>Generated by %s version %s.</em></p>\n" "</body>\n" "<p><em>Generated by %s version %s.</em></p>\n" "</body>\n"
"</html>\n", "</html>\n",
PACKAGE, VERSION, PACKAGE, VERSION, PACKAGE, VERSION, PACKAGE, VERSION,
stats->num_open, stats->num_open,
stats->num_reqs, stats->num_reqs,
stats->num_badcons, stats->num_denied, stats->num_badcons, stats->num_denied,
stats->num_refused, PACKAGE, VERSION); stats->num_refused, PACKAGE, VERSION);
if (send_http_message (connptr, 200, "OK", if (send_http_message (connptr, 200, "OK", message_buffer) < 0) {
message_buffer) < 0) {
safefree (message_buffer); safefree (message_buffer);
return -1; return -1;
} }

View File

@ -111,21 +111,21 @@ do_transparent_proxy (struct conn_s *connptr, hashmap_t hashofheaders,
return 1; return 1;
} }
for (i = 0; i < vector_length(conf->listen_addrs); i++) { for (i = 0; i < vector_length (conf->listen_addrs); i++) {
const char *addr; const char *addr;
addr = (char *)vector_getentry(conf->listen_addrs, i, NULL); addr = (char *) vector_getentry (conf->listen_addrs, i, NULL);
if (addr && strcmp(request->host, addr) == 0) { if (addr && strcmp (request->host, addr) == 0) {
log_message(LOG_ERR, log_message (LOG_ERR,
"transparent: destination IP %s is local " "transparent: destination IP %s is local "
"on socket fd %d", "on socket fd %d",
request->host, connptr->client_fd); request->host, connptr->client_fd);
indicate_http_error(connptr, 400, "Bad Request", indicate_http_error (connptr, 400, "Bad Request",
"detail", "detail",
"You tried to connect to the " "You tried to connect to the "
"machine the proxy is running on", "machine the proxy is running on",
"url", *url, NULL); "url", *url, NULL);
return 0; return 0;
} }
} }

View File

@ -31,6 +31,25 @@
#include "basicauth.h" #include "basicauth.h"
#ifdef UPSTREAM_SUPPORT #ifdef UPSTREAM_SUPPORT
static const char *proxy_list_name (struct upstream_proxy_list *plist)
{
#define MAXBUF ((size_t)(1024 * 96))
static char hostport[MAXBUF];
static char pbuffer[MAXBUF];
struct upstream_proxy_list *upl = plist;
bzero (&pbuffer, MAXBUF);
snprintf (pbuffer, MAXBUF, "%s:%d", upl->host, upl->port);
upl = upl->next;
while (upl) {
bzero (&hostport, MAXBUF);
snprintf (hostport, MAXBUF, "|%s:%d", upl->host, upl->port);
strncat (pbuffer, hostport, MAXBUF - strlen (hostport));
upl = upl->next;
}
return pbuffer;
}
const char *proxy_type_name (proxy_type type) const char *proxy_type_name (proxy_type type)
{ {
switch (type) { switch (type) {
@ -47,15 +66,43 @@ const char *proxy_type_name (proxy_type type)
} }
} }
static struct upstream_proxy_list *uplcpy (const struct upstream_proxy_list
*plist)
{
struct upstream_proxy_list *upr, *upp, *uptr;
if (!plist)
return NULL;
upr = upp = (upstream_proxy_list_t *)
safemalloc (sizeof (upstream_proxy_list_t));
upp->host = safestrdup (plist->host);
upp->port = plist->port;
upp->last_failed_connect = plist->last_failed_connect;
upp->next = NULL;
uptr = plist->next;
while (uptr) {
upp->next = (upstream_proxy_list_t *)
safemalloc (sizeof (upstream_proxy_list_t));
upp = upp->next;
upp->host = safestrdup (uptr->host);
upp->port = uptr->port;
upp->next = NULL;
uptr = uptr->next;
}
return upr;
}
/** /**
* Construct an upstream struct from input data. * Construct an upstream struct from input data.
*/ */
static struct upstream *upstream_build (const char *host, int port, static struct upstream *upstream_build (const struct upstream_proxy_list *plist,
const char *domain, const char *user, const char *domain, const char *user,
const char *pass, proxy_type type) const char *pass, proxy_type type)
{ {
char *ptr; char *ptr;
struct upstream *up; struct upstream *up;
struct upstream_proxy_list *upp;
#ifdef UPSTREAM_REGEX #ifdef UPSTREAM_REGEX
int cflags = REG_NEWLINE | REG_NOSUB; int cflags = REG_NEWLINE | REG_NOSUB;
int rflag = 0; int rflag = 0;
@ -70,7 +117,8 @@ static struct upstream *upstream_build (const char *host, int port,
} }
up->type = type; up->type = type;
up->host = up->domain = up->ua.user = up->pass = NULL; up->domain = up->ua.user = up->pass = NULL;
up->plist = NULL;
#ifdef UPSTREAM_REGEX #ifdef UPSTREAM_REGEX
up->pat = NULL; up->pat = NULL;
up->cpat = NULL; up->cpat = NULL;
@ -124,18 +172,18 @@ static struct upstream *upstream_build (const char *host, int port,
} }
if (domain == NULL) { if (domain == NULL) {
if (!host || host[0] == '\0' || port < 1) { if (!plist || plist->host[0] == '\0' || plist->port < 1) {
log_message (LOG_WARNING, log_message (LOG_WARNING,
"Nonsense upstream rule: invalid host or port"); "Nonsense upstream rule: invalid host or port");
goto fail; goto fail;
} }
up->host = safestrdup (host); up->plist = uplcpy (plist);
up->port = port;
log_message (LOG_INFO, "Added upstream %s %s:%d for [default]", log_message (LOG_INFO, "Added upstream %s %s for [default]",
proxy_type_name (type), host, port); proxy_type_name (type),
} else if (host == NULL || type == PT_NONE) { proxy_list_name (up->plist));
} else if (plist == NULL || type == PT_NONE) {
if (!domain || domain[0] == '\0') { if (!domain || domain[0] == '\0') {
log_message (LOG_WARNING, log_message (LOG_WARNING,
"Nonsense no-upstream rule: empty domain"); "Nonsense no-upstream rule: empty domain");
@ -183,15 +231,14 @@ static struct upstream *upstream_build (const char *host, int port,
log_message (LOG_INFO, "Added no-upstream for %s", domain); log_message (LOG_INFO, "Added no-upstream for %s", domain);
} else { } else {
if (!host || host[0] == '\0' || port < 1 || !domain if (!plist || plist->host[0] == '\0' || plist->port < 1
|| domain[0] == '\0') { || !domain || domain[0] == '\0') {
log_message (LOG_WARNING, log_message (LOG_WARNING,
"Nonsense upstream rule: invalid parameters"); "Nonsense upstream rule: invalid parameters");
goto fail; goto fail;
} }
up->host = safestrdup (host); up->plist = uplcpy (plist);
up->port = port;
up->domain = safestrdup (domain); up->domain = safestrdup (domain);
#ifdef UPSTREAM_REGEX #ifdef UPSTREAM_REGEX
if (rflag) { if (rflag) {
@ -205,19 +252,29 @@ static struct upstream *upstream_build (const char *host, int port,
} }
} }
#endif #endif
log_message (LOG_INFO, "Added upstream %s %s:%d for %s", log_message (LOG_INFO, "Added upstream %s %s for %s",
proxy_type_name (type), host, port, domain); proxy_type_name (type),
proxy_list_name (up->plist), domain);
} }
return up; return up;
fail: fail:
safefree (up->ua.user); safefree (up->ua.user);
safefree (up->ua.authstr);
safefree (up->pass); safefree (up->pass);
safefree (up->host); upp = up->plist;
while (upp) {
struct upstream_proxy_list *tmpp = upp;
upp = upp->next;
safefree (tmpp->host);
safefree (tmpp);
}
safefree (up->domain); safefree (up->domain);
#ifdef UPSTREAM_REGEX #ifdef UPSTREAM_REGEX
safefree (up->pat); safefree (up->pat);
if (up->cpat)
regfree (up->cpat);
safefree (up->cpat); safefree (up->cpat);
#endif #endif
safefree (up); safefree (up);
@ -228,13 +285,14 @@ fail:
/* /*
* Add an entry to the upstream list * Add an entry to the upstream list
*/ */
void upstream_add (const char *host, int port, const char *domain, void upstream_add (const struct upstream_proxy_list *plist, const char *domain,
const char *user, const char *pass, const char *user, const char *pass,
proxy_type type, struct upstream **upstream_list) proxy_type type, struct upstream **upstream_list)
{ {
struct upstream *up; struct upstream *up;
struct upstream_proxy_list *upp;
up = upstream_build (host, port, domain, user, pass, type); up = upstream_build (plist, domain, user, pass, type);
if (up == NULL) { if (up == NULL) {
return; return;
} }
@ -265,8 +323,23 @@ void upstream_add (const char *host, int port, const char *domain,
return; return;
upstream_cleanup: upstream_cleanup:
safefree (up->host); upp = up->plist;
while (upp) {
struct upstream_proxy_list *tmpp = upp;
upp = upp->next;
safefree (tmpp->host);
safefree (tmpp);
}
safefree (up->domain); safefree (up->domain);
safefree (up->ua.user);
safefree (up->ua.authstr);
safefree (up->pass);
#ifdef UPSTREAM_REGEX
safefree (up->pat);
if (up->cpat)
regfree (up->cpat);
safefree (up->cpat);
#endif
safefree (up); safefree (up);
return; return;
@ -323,14 +396,14 @@ struct upstream *upstream_get (struct request_s *request, struct upstream *up)
up = up->next; up = up->next;
} }
if (up && !up->plist)
if (up && (!up->host || !up->port))
up = NULL; up = NULL;
if (up) if (up)
log_message (LOG_INFO, "Found upstream proxy %s %s:%d for %s", log_message (LOG_INFO,
proxy_type_name (up->type), up->host, up->port, "Found upstream proxy/proxies %s %s for %s",
host); proxy_type_name (up->type),
proxy_list_name (up->plist), host);
else else
log_message (LOG_INFO, "No upstream proxy for %s", host); log_message (LOG_INFO, "No upstream proxy for %s", host);
@ -341,9 +414,24 @@ void free_upstream_list (struct upstream *up)
{ {
while (up) { while (up) {
struct upstream *tmp = up; struct upstream *tmp = up;
struct upstream_proxy_list *upp = up->plist;
up = up->next; up = up->next;
while (upp) {
struct upstream_proxy_list *tmpp = upp;
upp = upp->next;
safefree (tmpp->host);
safefree (tmpp);
}
safefree (tmp->domain); safefree (tmp->domain);
safefree (tmp->host); safefree (tmp->ua.user);
safefree (tmp->ua.authstr);
safefree (tmp->pass);
#ifdef UPSTREAM_REGEX
safefree (tmp->pat);
if (tmp->cpat)
regfree (tmp->cpat);
safefree (tmp->cpat);
#endif
safefree (tmp); safefree (tmp);
} }
} }

View File

@ -39,16 +39,25 @@ typedef enum proxy_type {
PT_SOCKS5 PT_SOCKS5
} proxy_type; } proxy_type;
typedef struct upstream_proxy_list {
struct upstream_proxy_list *next;
char *host;
int port;
time_t last_failed_connect;
} upstream_proxy_list_t;
struct upstream { struct upstream {
struct upstream *next; struct upstream *next;
char *domain; /* optional */ char *domain; /* optional */
struct upstream_proxy_list *plist;
char *host; char *host;
int port;
union { union {
char *user; char *user;
char *authstr; char *authstr;
} ua; } ua;
char *pass; char *pass;
int port;
in_addr_t ip, mask; in_addr_t ip, mask;
proxy_type type; proxy_type type;
#if defined(UPSTREAM_SUPPORT) && defined(UPSTREAM_REGEX) #if defined(UPSTREAM_SUPPORT) && defined(UPSTREAM_REGEX)
@ -59,9 +68,10 @@ struct upstream {
#ifdef UPSTREAM_SUPPORT #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, extern void upstream_add (const struct upstream_proxy_list *phost,
const char *user, const char *pass, const char *domain, const char *user,
proxy_type type, struct upstream **upstream_list); const char *pass, proxy_type type,
struct upstream **upstream_list);
extern struct upstream *upstream_get (struct request_s *request, extern struct upstream *upstream_get (struct request_s *request,
struct upstream *up); struct upstream *up);
extern void free_upstream_list (struct upstream *up); extern void free_upstream_list (struct upstream *up);

View File

@ -185,8 +185,7 @@ int create_file_safely (const char *filename, unsigned int truncate_file)
* *
* Returns: %0 on success, non-zero values on errors. * Returns: %0 on success, non-zero values on errors.
**/ **/
int int pidfile_create (const char *filename)
pidfile_create (const char *filename)
{ {
int fildes; int fildes;
FILE *fd; FILE *fd;

View File

@ -111,10 +111,7 @@ typedef enum {
} vector_pos_t; } vector_pos_t;
static int static int
vector_insert (vector_t vector, vector_insert (vector_t vector, void *data, size_t len, vector_pos_t pos)
void *data,
size_t len,
vector_pos_t pos)
{ {
struct vectorentry_s *entry; struct vectorentry_s *entry;