diff --git a/docs/man5/tinyproxy.conf.txt.in b/docs/man5/tinyproxy.conf.txt.in index b3b94ec..1c2aea5 100644 --- a/docs/man5/tinyproxy.conf.txt.in +++ b/docs/man5/tinyproxy.conf.txt.in @@ -72,6 +72,11 @@ The possible keywords and their descriptions are as follows: The maximum number of seconds of inactivity a connection is 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*:: 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: * '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 - 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 - 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`. @@ -173,6 +182,11 @@ The possible keywords and their descriptions are as follows: * '.' matches any host with no domain (in 'empty' domain) * 'IP/bits' matches network/mask * 'IP/mask' matches network/mask + * 'regex()' matches against basic case senstive regular expression + * 'regexe()' matches against extended case senstive regular expression + * 'regexi()' matches against basic case insenstive regular expression + * 'regexei()' matches against extended case insenstive regular expression + * 'regexie()' matches against extended case insenstive regular expression *MaxClients*:: diff --git a/src/acl.c b/src/acl.c index b7a334c..13700df 100644 --- a/src/acl.c +++ b/src/acl.c @@ -111,7 +111,7 @@ fill_netmask_array (char *bitmask_string, int v6, /** * 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) { *access_list = vector_create (); @@ -143,7 +143,7 @@ insert_acl (char *location, acl_access_t access_type, vector_t *access_list) assert (location != NULL); - ret = init_access_list(access_list); + ret = init_access_list (access_list); if (ret != 0) { return -1; } @@ -170,7 +170,7 @@ insert_acl (char *location, acl_access_t access_type, vector_t *access_list) */ p = strchr (location, '/'); if (p != NULL) { - char dst[sizeof(struct in6_addr)]; + char dst[sizeof (struct in6_addr)]; 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 * an IPv6 address */ - if (inet_pton(AF_INET6, location, dst) > 0) + if (inet_pton (AF_INET6, location, dst) > 0) v6 = 1; else 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++) acl.address.ip.network[i] = ip_dst[i] & - acl.address.ip.mask[i]; + acl.address.ip.mask[i]; } else { /* In all likelihood a string */ acl.type = ACL_STRING; diff --git a/src/base64.c b/src/base64.c index cc9b6ae..1f0f643 100644 --- a/src/base64.c +++ b/src/base64.c @@ -19,7 +19,7 @@ #include "base64.h" static const char base64_tbl[64] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* 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. 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; - char* d = dst; - while(count) { - int i = 0, n = *s << 16; - s++; - count--; - if(count) { - n |= *s << 8; - s++; - count--; - i++; - } - if(count) { - n |= *s; - s++; - count--; - i++; - } - *d++ = base64_tbl[(n >> 18) & 0x3f]; - *d++ = base64_tbl[(n >> 12) & 0x3f]; - *d++ = i ? base64_tbl[(n >> 6) & 0x3f] : '='; - *d++ = i == 2 ? base64_tbl[n & 0x3f] : '='; - } - *d = 0; + unsigned const char *s = src; + char *d = dst; + while (count) { + int i = 0, n = *s << 16; + s++; + count--; + if (count) { + n |= *s << 8; + s++; + count--; + i++; + } + if (count) { + n |= *s; + s++; + count--; + i++; + } + *d++ = base64_tbl[(n >> 18) & 0x3f]; + *d++ = base64_tbl[(n >> 12) & 0x3f]; + *d++ = i ? base64_tbl[(n >> 6) & 0x3f] : '='; + *d++ = i == 2 ? base64_tbl[n & 0x3f] : '='; + } + *d = 0; } - diff --git a/src/base64.h b/src/base64.h index 4465b9e..3d58da5 100644 --- a/src/base64.h +++ b/src/base64.h @@ -23,7 +23,6 @@ /* calculates number of bytes base64-encoded stream of N bytes will take. */ #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 - diff --git a/src/basicauth.c b/src/basicauth.c index d6c2420..ac81ff8 100644 --- a/src/basicauth.c +++ b/src/basicauth.c @@ -32,29 +32,31 @@ * -1 if user/pass missing * 0 if user/pass too long */ -ssize_t basicauth_string(const char *user, const char *pass, - char *buf, size_t bufsize) +ssize_t basicauth_string (const char *user, const char *pass, + char *buf, size_t bufsize) { - char tmp[256+2]; - int l; - if (!user || !pass) return -1; - l = snprintf(tmp, sizeof tmp, "%s:%s", user, pass); - if (l < 0 || l >= (ssize_t) sizeof tmp) return 0; - if (bufsize < (BASE64ENC_BYTES((unsigned)l) + 1)) return 0; - base64enc(buf, tmp, l); - return BASE64ENC_BYTES(l); + char tmp[256 + 2]; + int l; + if (!user || !pass) + return -1; + l = snprintf (tmp, sizeof tmp, "%s:%s", user, pass); + if (l < 0 || l >= (ssize_t) sizeof tmp) + return 0; + if (bufsize < (BASE64ENC_BYTES ((unsigned) l) + 1)) + return 0; + base64enc (buf, tmp, l); + return BASE64ENC_BYTES (l); } /* * Add entry to the basicauth list */ -void basicauth_add (vector_t authlist, - const char *user, const char *pass) +void basicauth_add (vector_t authlist, const char *user, const char *pass) { - char b[BASE64ENC_BYTES((256+2)-1) + 1]; - ssize_t ret; + 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 == -1) { log_message (LOG_WARNING, "Illegal basicauth rule: missing user or pass"); @@ -65,14 +67,13 @@ void basicauth_add (vector_t authlist, return; } - if (vector_append(authlist, b, ret + 1) == -ENOMEM) { + if (vector_append (authlist, b, ret + 1) == -ENOMEM) { log_message (LOG_ERR, "Unable to allocate memory in basicauth_add()"); return; } - log_message (LOG_INFO, - "Added basic auth user : %s", user); + log_message (LOG_INFO, "Added basic auth user : %s", user); } /* @@ -84,15 +85,16 @@ int basicauth_check (vector_t authlist, const char *authstring) { ssize_t vl, i; size_t el; - const char* entry; + const char *entry; vl = vector_length (authlist); - if (vl == -EINVAL) return 0; + if (vl == -EINVAL) + return 0; for (i = 0; i < vl; i++) { entry = vector_getentry (authlist, i, &el); if (strcmp (authstring, entry) == 0) return 1; } - return 0; + return 0; } diff --git a/src/basicauth.h b/src/basicauth.h index 61dc5c3..9818f34 100644 --- a/src/basicauth.h +++ b/src/basicauth.h @@ -24,11 +24,11 @@ #include #include "vector.h" -extern ssize_t basicauth_string(const char *user, const char *pass, - char *buf, size_t bufsize); +extern ssize_t basicauth_string (const char *user, const char *pass, + char *buf, size_t bufsize); 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); diff --git a/src/buffer.c b/src/buffer.c index b338183..b2c88c2 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -244,9 +244,9 @@ ssize_t read_buffer (int fd, struct buffer_s * buffptr) #ifdef EWOULDBLOCK case EWOULDBLOCK: #else -# ifdef EAGAIN +#ifdef EAGAIN case EAGAIN: -# endif +#endif #endif case EINTR: bytesin = 0; @@ -254,7 +254,7 @@ ssize_t read_buffer (int fd, struct buffer_s * buffptr) default: log_message (LOG_ERR, "read_buffer: read() failed on fd %d: %s", - fd, strerror(errno)); + fd, strerror (errno)); bytesin = -1; break; } @@ -298,9 +298,9 @@ ssize_t write_buffer (int fd, struct buffer_s * buffptr) #ifdef EWOULDBLOCK case EWOULDBLOCK: #else -# ifdef EAGAIN +#ifdef EAGAIN case EAGAIN: -# endif +#endif #endif case EINTR: return 0; diff --git a/src/child.c b/src/child.c index 60f8ead..c241593 100644 --- a/src/child.c +++ b/src/child.c @@ -192,7 +192,7 @@ static void child_main (struct child_s *ptr) int ret; cliaddr = (struct sockaddr *) - safemalloc (sizeof(struct sockaddr_storage)); + safemalloc (sizeof (struct sockaddr_storage)); if (!cliaddr) { log_message (LOG_CRIT, "Could not allocate memory for child address."); @@ -200,7 +200,7 @@ static void child_main (struct child_s *ptr) } ptr->connects = 0; - srand(time(NULL)); + srand (time (NULL)); /* * We have to wait for connections on multiple fds, @@ -210,45 +210,46 @@ static void child_main (struct child_s *ptr) int listenfd = -1; - FD_ZERO(&rfds); + FD_ZERO (&rfds); - for (i = 0; i < vector_length(listen_fds); i++) { - int *fd = (int *) vector_getentry(listen_fds, i, NULL); + for (i = 0; i < vector_length (listen_fds); i++) { + int *fd = (int *) vector_getentry (listen_fds, i, NULL); - ret = socket_nonblocking(*fd); + ret = socket_nonblocking (*fd); if (ret != 0) { - log_message(LOG_ERR, "Failed to set the listening " - "socket %d to non-blocking: %s", - fd, strerror(errno)); - exit(1); + log_message (LOG_ERR, + "Failed to set the listening " + "socket %d to non-blocking: %s", + fd, strerror (errno)); + exit (1); } - FD_SET(*fd, &rfds); - maxfd = max(maxfd, *fd); + FD_SET (*fd, &rfds); + maxfd = max (maxfd, *fd); } 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 (errno == EINTR) { continue; } log_message (LOG_ERR, "error calling select: %s", - strerror(errno)); - exit(1); + strerror (errno)); + exit (1); } else if (ret == 0) { log_message (LOG_WARNING, "Strange: select returned 0 " "but we did not specify a timeout..."); continue; } - for (i = 0; i < vector_length(listen_fds); i++) { - int *fd = (int *) vector_getentry(listen_fds, i, NULL); + for (i = 0; i < vector_length (listen_fds); i++) { + 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 * fd that we find readable. - fair? @@ -259,17 +260,17 @@ static void child_main (struct child_s *ptr) } if (listenfd == -1) { - log_message(LOG_WARNING, "Strange: None of our listen " - "fds was readable after select"); + log_message (LOG_WARNING, "Strange: None of our listen " + "fds was readable after select"); continue; } - ret = socket_blocking(listenfd); + ret = socket_blocking (listenfd); if (ret != 0) { - log_message(LOG_ERR, "Failed to set listening " - "socket %d to blocking for accept: %s", - listenfd, strerror(errno)); - exit(1); + log_message (LOG_ERR, "Failed to set listening " + "socket %d to blocking for accept: %s", + listenfd, strerror (errno)); + exit (1); } /* @@ -539,11 +540,10 @@ void child_kill_children (int sig) } } - /** * 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; ssize_t i; @@ -551,7 +551,7 @@ int child_listening_sockets(vector_t listen_addrs, uint16_t port) assert (port > 0); if (listen_fds == NULL) { - listen_fds = vector_create(); + listen_fds = vector_create (); if (listen_fds == NULL) { log_message (LOG_ERR, "Could not create the list " "of listening fds"); @@ -559,28 +559,26 @@ int child_listening_sockets(vector_t listen_addrs, uint16_t port) } } - if ((listen_addrs == NULL) || - (vector_length(listen_addrs) == 0)) - { + if ((listen_addrs == NULL) || (vector_length (listen_addrs) == 0)) { /* * no Listen directive: * listen on the wildcard address(es) */ - ret = listen_sock(NULL, port, listen_fds); + ret = listen_sock (NULL, port, listen_fds); return ret; } - for (i = 0; i < vector_length(listen_addrs); i++) { + for (i = 0; i < vector_length (listen_addrs); i++) { const char *addr; - addr = (char *)vector_getentry(listen_addrs, i, NULL); + addr = (char *) vector_getentry (listen_addrs, i, NULL); if (addr == NULL) { - log_message(LOG_WARNING, - "got NULL from listen_addrs - skipping"); + log_message (LOG_WARNING, + "got NULL from listen_addrs - skipping"); continue; } - ret = listen_sock(addr, port, listen_fds); + ret = listen_sock (addr, port, listen_fds); if (ret != 0) { return ret; } @@ -593,12 +591,12 @@ void child_close_sock (void) { ssize_t i; - for (i = 0; i < vector_length(listen_fds); i++) { - int *fd = (int *) vector_getentry(listen_fds, i, NULL); + for (i = 0; i < vector_length (listen_fds); i++) { + int *fd = (int *) vector_getentry (listen_fds, i, NULL); close (*fd); } - vector_delete(listen_fds); + vector_delete (listen_fds); listen_fds = NULL; } diff --git a/src/common.h b/src/common.h index 47a1ed1..0d65af4 100644 --- a/src/common.h +++ b/src/common.h @@ -26,7 +26,7 @@ #define COMMON_HEADER_H #ifdef HAVE_CONFIG_H -# include +#include #endif /* @@ -42,57 +42,57 @@ #include #include /* standard POSIX headers - they need to be there as well. */ -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* rest - some oddball headers */ #ifdef HAVE_VALUES_H -# include +#include #endif #ifdef HAVE_SYS_IOCTL_H -# include +#include #endif #ifdef HAVE_ALLOCA_H -# include +#include #endif #ifdef HAVE_MEMORY_H -# include +#include #endif #ifdef HAVE_MALLOC_H -# include +#include #endif #ifdef HAVE_SYSEXITS_H -# include +#include #endif /* @@ -100,13 +100,13 @@ * cause any problems. */ #ifndef MSG_NOSIGNAL -# define MSG_NOSIGNAL (0) +#define MSG_NOSIGNAL (0) #endif #ifndef SHUT_RD /* these three Posix.1g names are quite new */ -# define SHUT_RD 0 /* shutdown for reading */ -# define SHUT_WR 1 /* shutdown for writing */ -# define SHUT_RDWR 2 /* shutdown for reading and writing */ +#define SHUT_RD 0 /* shutdown for reading */ +#define SHUT_WR 1 /* shutdown for writing */ +#define SHUT_RDWR 2 /* shutdown for reading and writing */ #endif #define MAXLISTEN 1024 /* Max number of connections */ @@ -115,19 +115,19 @@ * SunOS doesn't have INADDR_NONE defined. */ #ifndef INADDR_NONE -# define INADDR_NONE -1 +#define INADDR_NONE -1 #endif /* Define boolean values */ #ifndef FALSE -# define FALSE 0 -# define TRUE (!FALSE) +#define FALSE 0 +#define TRUE (!FALSE) #endif /* Useful function macros */ #if !defined(min) || !defined(max) -# define min(a,b) ((a) < (b) ? (a) : (b)) -# define max(a,b) ((a) > (b) ? (a) : (b)) +#define min(a,b) ((a) < (b) ? (a) : (b)) +#define max(a,b) ((a) > (b) ? (a) : (b)) #endif #endif diff --git a/src/conf.c b/src/conf.c index 5ebf179..e3c1589 100644 --- a/src/conf.c +++ b/src/conf.c @@ -80,13 +80,14 @@ #define IPV6MASK "(" IPV6 "(/[[:digit:]]+)?)" #define BEGIN "^[[:space:]]*" #define END "[[:space:]]*$" +#define PIPE "\\|" /* * Limit the maximum number of substring matches to a reasonably high * number. Given the usual structure of the configuration file, sixteen * substring matches should be plenty. */ -#define RE_MAX_MATCHES 16 +#define RE_MAX_MATCHES 50 /* * All configuration handling functions are REQUIRED to be defined @@ -163,6 +164,7 @@ static HANDLE_FUNC (handle_disableviaheader); static HANDLE_FUNC (handle_xtinyproxy); #ifdef UPSTREAM_SUPPORT +static HANDLE_FUNC (handle_deadtime); static HANDLE_FUNC (handle_upstream); static HANDLE_FUNC (handle_upstream_no); #endif @@ -195,91 +197,89 @@ struct { } directives[] = { /* comments */ { - BEGIN "#", handle_nop, NULL - }, - /* blank lines */ + BEGIN "#", handle_nop, NULL}, + /* blank lines */ { - "^[[:space:]]+$", handle_nop, NULL - }, - /* string arguments */ - STDCONF ("logfile", STR, handle_logfile), - STDCONF ("pidfile", STR, handle_pidfile), - STDCONF ("anonymous", STR, handle_anonymous), - STDCONF ("viaproxyname", STR, handle_viaproxyname), - STDCONF ("defaulterrorfile", STR, handle_defaulterrorfile), - STDCONF ("statfile", STR, handle_statfile), - STDCONF ("stathost", STR, handle_stathost), - STDCONF ("xtinyproxy", BOOL, handle_xtinyproxy), - /* boolean arguments */ - STDCONF ("syslog", BOOL, handle_syslog), - STDCONF ("bindsame", BOOL, handle_bindsame), - STDCONF ("disableviaheader", BOOL, handle_disableviaheader), - /* integer arguments */ - STDCONF ("port", INT, handle_port), - STDCONF ("maxclients", INT, handle_maxclients), - STDCONF ("maxspareservers", INT, handle_maxspareservers), - STDCONF ("minspareservers", INT, handle_minspareservers), - STDCONF ("startservers", INT, handle_startservers), - STDCONF ("maxrequestsperchild", INT, handle_maxrequestsperchild), - STDCONF ("timeout", INT, handle_timeout), - STDCONF ("connectport", INT, handle_connectport), - /* alphanumeric arguments */ - STDCONF ("user", ALNUM, handle_user), - STDCONF ("group", ALNUM, handle_group), - /* ip arguments */ - STDCONF ("listen", "(" IP "|" IPV6 ")", handle_listen), - STDCONF ("allow", "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")", - handle_allow), - STDCONF ("deny", "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")", - handle_deny), - STDCONF ("bind", "(" IP "|" IPV6 ")", handle_bind), - /* other */ - STDCONF ("basicauth", ALNUM WS ALNUM, handle_basicauth), - STDCONF ("errorfile", INT WS STR, handle_errorfile), - STDCONF ("addheader", STR WS STR, handle_addheader), - + "^[[:space:]]+$", handle_nop, NULL}, + /* string arguments */ + STDCONF ("logfile", STR, handle_logfile), + STDCONF ("pidfile", STR, handle_pidfile), + STDCONF ("anonymous", STR, handle_anonymous), + STDCONF ("viaproxyname", STR, handle_viaproxyname), + STDCONF ("defaulterrorfile", STR, handle_defaulterrorfile), + STDCONF ("statfile", STR, handle_statfile), + STDCONF ("stathost", STR, handle_stathost), + STDCONF ("xtinyproxy", BOOL, handle_xtinyproxy), + /* boolean arguments */ + STDCONF ("syslog", BOOL, handle_syslog), + STDCONF ("bindsame", BOOL, handle_bindsame), + STDCONF ("disableviaheader", BOOL, handle_disableviaheader), + /* integer arguments */ + STDCONF ("port", INT, handle_port), + STDCONF ("maxclients", INT, handle_maxclients), + STDCONF ("maxspareservers", INT, handle_maxspareservers), + STDCONF ("minspareservers", INT, handle_minspareservers), + STDCONF ("startservers", INT, handle_startservers), + STDCONF ("maxrequestsperchild", INT, handle_maxrequestsperchild), + STDCONF ("timeout", INT, handle_timeout), +#ifdef UPSTREAM_SUPPORT + STDCONF ("deadtime", INT, handle_deadtime), +#endif + STDCONF ("connectport", INT, handle_connectport), + /* alphanumeric arguments */ + STDCONF ("user", ALNUM, handle_user), + STDCONF ("group", ALNUM, handle_group), + /* ip arguments */ + STDCONF ("listen", "(" IP "|" IPV6 ")", handle_listen), + STDCONF ("allow", "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")", + handle_allow), + STDCONF ("deny", "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")", + handle_deny), + STDCONF ("bind", "(" IP "|" IPV6 ")", handle_bind), + /* other */ + STDCONF ("basicauth", ALNUM WS ALNUM, handle_basicauth), + STDCONF ("errorfile", INT WS STR, handle_errorfile), + STDCONF ("addheader", STR WS STR, handle_addheader), #ifdef FILTER_ENABLE - /* filtering */ - STDCONF ("filter", STR, handle_filter), - STDCONF ("filterurls", BOOL, handle_filterurls), - STDCONF ("filterextended", BOOL, handle_filterextended), - STDCONF ("filterdefaultdeny", BOOL, handle_filterdefaultdeny), - STDCONF ("filtercasesensitive", BOOL, handle_filtercasesensitive), + /* filtering */ + STDCONF ("filter", STR, handle_filter), + STDCONF ("filterurls", BOOL, handle_filterurls), + STDCONF ("filterextended", BOOL, handle_filterextended), + STDCONF ("filterdefaultdeny", BOOL, handle_filterdefaultdeny), + STDCONF ("filtercasesensitive", BOOL, handle_filtercasesensitive), #endif #ifdef REVERSE_SUPPORT - /* Reverse proxy arguments */ - STDCONF ("reversebaseurl", STR, handle_reversebaseurl), - STDCONF ("reverseonly", BOOL, handle_reverseonly), - STDCONF ("reversemagic", BOOL, handle_reversemagic), - STDCONF ("reversepath", STR "(" WS STR ")?", handle_reversepath), + /* Reverse proxy arguments */ + STDCONF ("reversebaseurl", STR, handle_reversebaseurl), + STDCONF ("reverseonly", BOOL, handle_reverseonly), + STDCONF ("reversemagic", BOOL, handle_reversemagic), + STDCONF ("reversepath", STR "(" WS STR ")?", handle_reversepath), #endif #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 - "(" USERNAME /*username*/ ":" PASSWORD /*password*/ "@" ")?" - "(" IP "|" ALNUM ")" - ":" INT "(" WS STR ")?" - END, handle_upstream, NULL - }, + "(" USERNAME /*username */ ":" PASSWORD /*password */ "@" + ")?" + "(" IP "|" ALNUM ")" ":" INT "(" "(" PIPE "(" IP + "|" ALNUM ")" ":" INT ")+" ")?" "(" WS STR ")?" + END, handle_upstream, NULL}, #endif - /* loglevel */ - STDCONF ("loglevel", "(critical|error|warning|notice|connect|info)", - handle_loglevel) + /* loglevel */ + STDCONF ("loglevel", "(critical|error|warning|notice|connect|info)", + handle_loglevel) }; const unsigned int ndirectives = sizeof (directives) / sizeof (directives[0]); -static void -free_added_headers (vector_t add_headers) +static void free_added_headers (vector_t add_headers) { ssize_t i; for (i = 0; i < vector_length (add_headers); i++) { http_header_t *header = (http_header_t *) - vector_getentry (add_headers, i, NULL); + vector_getentry (add_headers, i, NULL); safefree (header->name); safefree (header->value); @@ -288,25 +288,25 @@ free_added_headers (vector_t 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->logf_name); safefree (conf->stathost); safefree (conf->user); safefree (conf->group); - vector_delete(conf->listen_addrs); - vector_delete(conf->basicauth_list); + vector_delete (conf->listen_addrs); + vector_delete (conf->basicauth_list); #ifdef FILTER_ENABLE safefree (conf->filter); -#endif /* FILTER_ENABLE */ +#endif /* FILTER_ENABLE */ #ifdef REVERSE_SUPPORT - free_reversepath_list(conf->reversepath_list); + free_reversepath_list (conf->reversepath_list); safefree (conf->reversebaseurl); #endif #ifdef UPSTREAM_SUPPORT free_upstream_list (conf->upstream_list); -#endif /* UPSTREAM_SUPPORT */ +#endif /* UPSTREAM_SUPPORT */ safefree (conf->pidpath); safefree (conf->bind_address); safefree (conf->via_proxy_name); @@ -318,7 +318,7 @@ static void free_config (struct config_s *conf) free_connect_ports_list (conf->connect_ports); 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. */ -int -config_compile_regex (void) +int config_compile_regex (void) { unsigned int i, r; @@ -356,8 +355,7 @@ config_compile_regex (void) * Frees pre-compiled regular expressions used by the configuration * file. This function is registered to be automatically called at exit. */ -static void -config_free_regex (void) +static void config_free_regex (void) { unsigned int i; @@ -384,7 +382,6 @@ static int check_match (struct config_s *conf, const char *line) unsigned int i; assert (ndirectives > 0); - for (i = 0; i != ndirectives; ++i) { assert (directives[i].cre); if (!regexec @@ -476,17 +473,16 @@ static void initialize_with_defaults (struct config_s *conf, if (defaults->listen_addrs) { ssize_t i; - conf->listen_addrs = vector_create(); - for (i=0; i < vector_length(defaults->listen_addrs); i++) { + conf->listen_addrs = vector_create (); + for (i = 0; i < vector_length (defaults->listen_addrs); i++) { char *addr; size_t size; - addr = (char *)vector_getentry(defaults->listen_addrs, - i, &size); - vector_append(conf->listen_addrs, addr, size); + addr = (char *) vector_getentry (defaults->listen_addrs, + i, &size); + vector_append (conf->listen_addrs, addr, size); } } - #ifdef FILTER_ENABLE if (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_extended = defaults->filter_extended; conf->filter_casesensitive = defaults->filter_casesensitive; -#endif /* FILTER_ENABLE */ +#endif /* FILTER_ENABLE */ #ifdef XTINYPROXY_ENABLE conf->add_xtinyproxy = defaults->add_xtinyproxy; @@ -513,7 +509,7 @@ static void initialize_with_defaults (struct config_s *conf, #ifdef UPSTREAM_SUPPORT /* struct upstream *upstream_list; */ -#endif /* UPSTREAM_SUPPORT */ +#endif /* UPSTREAM_SUPPORT */ if (defaults->pidpath) { conf->pidpath = safestrdup (defaults->pidpath); @@ -521,6 +517,10 @@ static void initialize_with_defaults (struct config_s *conf, conf->idletimeout = defaults->idletimeout; +#ifdef UPSTREAM_SUPPORT + conf->deadtime = defaults->deadtime; +#endif + if (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); 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: return ret; @@ -659,8 +668,7 @@ set_bool_arg (unsigned int *var, const char *line, regmatch_t * match) return 0; } -static unsigned long -get_long_arg (const char *line, regmatch_t * match) +static unsigned long get_long_arg (const char *line, regmatch_t * match) { assert (line); 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); } -static int -set_int_arg (unsigned int *var, const char *line, regmatch_t * match) +static int set_int_arg (unsigned int *var, const char *line, regmatch_t * match) { assert (var); assert (line); @@ -726,8 +733,7 @@ static HANDLE_FUNC (handle_viaproxyname) if (r) return r; log_message (LOG_INFO, - "Setting \"Via\" header to '%s'", - conf->via_proxy_name); + "Setting \"Via\" header to '%s'", conf->via_proxy_name); return 0; } @@ -739,8 +745,7 @@ static HANDLE_FUNC (handle_disableviaheader) return r; } - log_message (LOG_INFO, - "Disabling transmission of the \"Via\" header."); + log_message (LOG_INFO, "Disabling transmission of the \"Via\" header."); return 0; } @@ -811,15 +816,13 @@ static HANDLE_FUNC (handle_maxclients) static HANDLE_FUNC (handle_maxspareservers) { - child_configure (CHILD_MAXSPARESERVERS, - get_long_arg (line, &match[2])); + child_configure (CHILD_MAXSPARESERVERS, get_long_arg (line, &match[2])); return 0; } static HANDLE_FUNC (handle_minspareservers) { - child_configure (CHILD_MINSPARESERVERS, - get_long_arg (line, &match[2])); + child_configure (CHILD_MINSPARESERVERS, get_long_arg (line, &match[2])); return 0; } @@ -841,6 +844,13 @@ static HANDLE_FUNC (handle_timeout) 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) { add_connect_port_allowed (get_long_arg (line, &match[2]), @@ -896,18 +906,18 @@ static HANDLE_FUNC (handle_listen) } if (conf->listen_addrs == NULL) { - conf->listen_addrs = vector_create(); - if (conf->listen_addrs == NULL) { - log_message(LOG_WARNING, "Could not create a list " - "of listen addresses."); - safefree(arg); - return -1; - } + conf->listen_addrs = vector_create (); + if (conf->listen_addrs == NULL) { + log_message (LOG_WARNING, "Could not create a list " + "of listen addresses."); + safefree (arg); + 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); return 0; @@ -994,10 +1004,10 @@ static HANDLE_FUNC (handle_loglevel) static HANDLE_FUNC (handle_basicauth) { char *user, *pass; - user = get_string_arg(line, &match[2]); + user = get_string_arg (line, &match[2]); if (!user) return -1; - pass = get_string_arg(line, &match[3]); + pass = get_string_arg (line, &match[3]); if (!pass) { safefree (user); return -1; @@ -1089,58 +1099,90 @@ static HANDLE_FUNC (handle_reversepath) #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] = { - [PT_NONE] = "none", - [PT_HTTP] = "http", - [PT_SOCKS4] = "socks4", - [PT_SOCKS5] = "socks5", - }; - unsigned i; - for (i = 0; i < sizeof(pt_map)/sizeof(pt_map[0]); i++) - if (!strcmp(pt_map[i], s)) - return i; - return PT_NONE; + static const char pt_map[][7] = { + [PT_NONE] = "none", + [PT_HTTP] = "http", + [PT_SOCKS4] = "socks4", + [PT_SOCKS5] = "socks5", + }; + unsigned i; + for (i = 0; i < sizeof (pt_map) / sizeof (pt_map[0]); i++) + if (!strcmp (pt_map[i], s)) + return i; + return PT_NONE; } static HANDLE_FUNC (handle_upstream) { - char *ip; - int port, mi = 2; + struct upstream_proxy_list *pltr, *plist; + int mi = 2; char *domain = 0, *user = 0, *pass = 0, *tmp; enum proxy_type pt; + pltr = plist = (upstream_proxy_list_t *) + safemalloc (sizeof (upstream_proxy_list_t)); tmp = get_string_arg (line, &match[mi]); - pt = pt_from_string(tmp); - safefree(tmp); + pt = pt_from_string (tmp); + safefree (tmp); mi += 2; if (match[mi].rm_so != -1) user = get_string_arg (line, &match[mi]); mi++; - if (match[mi].rm_so != -1) + if (match[mi].rm_so != -1) pass = get_string_arg (line, &match[mi]); mi++; - - ip = get_string_arg (line, &match[mi]); - if (!ip) + plist->host = get_string_arg (line, &match[mi]); + if (!plist->host) return -1; + 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 += 3; + mi += 2; + /* 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) 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 (pass); safefree (domain); - safefree (ip); + while (pltr) { + struct upstream_proxy_list *tmpp = pltr; + pltr = pltr->next; + safefree (tmpp->host); + safefree (tmpp); + } return 0; } @@ -1153,7 +1195,7 @@ static HANDLE_FUNC (handle_upstream_no) if (!domain) 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); return 0; diff --git a/src/conf.h b/src/conf.h index beb2b01..57b6243 100644 --- a/src/conf.h +++ b/src/conf.h @@ -55,7 +55,7 @@ struct config_s { unsigned int filter_casesensitive; /* boolean */ #endif /* FILTER_ENABLE */ #ifdef XTINYPROXY_ENABLE - unsigned int add_xtinyproxy; /* boolean */ + unsigned int add_xtinyproxy; /* boolean */ #endif #ifdef REVERSE_SUPPORT struct reversepath *reversepath_list; @@ -68,6 +68,9 @@ struct config_s { #endif /* UPSTREAM_SUPPORT */ char *pidpath; unsigned int idletimeout; +#ifdef UPSTREAM_SUPPORT + unsigned int deadtime; +#endif /* UPSTREAM_SUPPORT */ char *bind_address; unsigned int bindsame; @@ -116,6 +119,8 @@ struct config_s { extern int reload_config_file (const char *config_fname, struct config_s *conf, struct config_s *defaults); +extern void free_config (struct config_s *conf); + int config_compile_regex (void); #endif diff --git a/src/connect-ports.c b/src/connect-ports.c index 41b4e3d..46d15dd 100644 --- a/src/connect-ports.c +++ b/src/connect-ports.c @@ -25,7 +25,7 @@ * Now, this routine adds a "port" to the list. It also creates the list if * 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) { *connect_ports = vector_create (); @@ -53,8 +53,8 @@ int check_allowed_connect_ports (int port, vector_t connect_ports) int *data; /* - * The absence of ConnectPort options in the config file - * meanas that all ports are allowed for CONNECT. + * The absence of ConnectPort options in the config file + * meanas that all ports are allowed for CONNECT. */ if (!connect_ports) return 1; diff --git a/src/connect-ports.h b/src/connect-ports.h index 4b3aaf7..5136b19 100644 --- a/src/connect-ports.h +++ b/src/connect-ports.h @@ -24,7 +24,7 @@ #include "common.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); void free_connect_ports_list (vector_t connect_ports); diff --git a/src/daemon.c b/src/daemon.c index 41b821a..22a8377 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -41,10 +41,9 @@ void makedaemon (void) if (fork () != 0) exit (0); - if (chdir ("/") != 0) { - log_message (LOG_WARNING, - "Could not change directory to /"); - } + if (chdir ("/") != 0) { + log_message (LOG_WARNING, "Could not change directory to /"); + } umask (0177); diff --git a/src/filter.c b/src/filter.c index e18132e..3d5d937 100644 --- a/src/filter.c +++ b/src/filter.c @@ -104,13 +104,11 @@ void filter_init (void) if (*s == '\0') continue; - if (!p) /* head of list */ - fl = p = - (struct filter_list *) + if (!p) /* head of list */ + fl = p = (struct filter_list *) safecalloc (1, sizeof (struct filter_list)); - else { /* next entry */ - p->next = - (struct filter_list *) + else { /* next entry */ + p->next = (struct filter_list *) safecalloc (1, sizeof (struct filter_list)); p = p->next; } diff --git a/src/hashmap.c b/src/hashmap.c index 7793d08..eca5a21 100644 --- a/src/hashmap.c +++ b/src/hashmap.c @@ -104,7 +104,7 @@ hashmap_t hashmap_create (unsigned int nbuckets) if (!ptr) return NULL; - ptr->seed = (uint32_t)rand(); + ptr->seed = (uint32_t) rand (); ptr->size = nbuckets; ptr->buckets = (struct hashbucket_s *) safecalloc (nbuckets, sizeof (struct @@ -508,8 +508,7 @@ char *lookup_variable (hashmap_t map, const char *varname) if (hashmap_is_end (map, result_iter)) return (NULL); - if (hashmap_return_entry (map, result_iter, - &key, (void **) &data) < 0) + if (hashmap_return_entry (map, result_iter, &key, (void **) &data) < 0) return (NULL); return (data); diff --git a/src/heap.h b/src/heap.h index f3cf671..9f1e51f 100644 --- a/src/heap.h +++ b/src/heap.h @@ -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, unsigned long line); -# define safecalloc(x, y) debugging_calloc(x, y, __FILE__, __LINE__) -# define safemalloc(x) debugging_malloc(x, __FILE__, __LINE__) -# define saferealloc(x, y) debugging_realloc(x, y, __FILE__, __LINE__) -# define safestrdup(x) debugging_strdup(x, __FILE__, __LINE__) -# define safefree(x) (debugging_free(x, __FILE__, __LINE__), *(&(x)) = NULL) +#define safecalloc(x, y) debugging_calloc(x, y, __FILE__, __LINE__) +#define safemalloc(x) debugging_malloc(x, __FILE__, __LINE__) +#define saferealloc(x, y) debugging_realloc(x, y, __FILE__, __LINE__) +#define safestrdup(x) debugging_strdup(x, __FILE__, __LINE__) +#define safefree(x) (debugging_free(x, __FILE__, __LINE__), *(&(x)) = NULL) #else -# define safecalloc(x, y) calloc(x, y) -# define safemalloc(x) malloc(x) -# define saferealloc(x, y) realloc(x, y) -# define safefree(x) (free (x), *(&(x)) = NULL) -# define safestrdup(x) strdup(x) +#define safecalloc(x, y) calloc(x, y) +#define safemalloc(x) malloc(x) +#define saferealloc(x, y) realloc(x, y) +#define safefree(x) (free (x), *(&(x)) = NULL) +#define safestrdup(x) strdup(x) #endif diff --git a/src/html-error.c b/src/html-error.c index ee3c987..aa3b02f 100644 --- a/src/html-error.c +++ b/src/html-error.c @@ -86,8 +86,7 @@ static char *get_html_file (unsigned int errornum) /* * Send an already-opened file to the client with variable substitution. */ -int -send_html_file (FILE *infile, struct conn_s *connptr) +int send_html_file (FILE * infile, struct conn_s *connptr) { char *inbuf; char *varstart = NULL; @@ -105,8 +104,9 @@ send_html_file (FILE *infile, struct conn_s *connptr) if (in_variable) { *p = '\0'; varval = (const char *) - lookup_variable (connptr->error_variables, - varstart); + lookup_variable + (connptr->error_variables, + varstart); if (!varval) varval = "(unknown)"; 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[] = "HTTP/1.0 %d %s\r\n" "Server: %s/%s\r\n" - "Content-Type: text/html\r\n" - "%s" - "Connection: close\r\n" "\r\n"; + "Content-Type: text/html\r\n" "%s" "Connection: close\r\n" "\r\n"; const char p_auth_str[] = - "Proxy-Authenticate: Basic realm=\"" - PACKAGE_NAME "\"\r\n"; + "Proxy-Authenticate: Basic realm=\"" PACKAGE_NAME "\"\r\n"; const char w_auth_str[] = - "WWW-Authenticate: Basic realm=\"" - PACKAGE_NAME "\"\r\n"; + "WWW-Authenticate: Basic realm=\"" PACKAGE_NAME "\"\r\n"; - /* according to rfc7235, the 407 error must be accompanied by - a Proxy-Authenticate header field. */ - const char *add = code == 407 ? p_auth_str : (code == 401 ? w_auth_str : ""); + /* according to rfc7235, the 407 error must be accompanied by + * a Proxy-Authenticate header field. */ + const char *add = + code == 407 ? p_auth_str : (code == 401 ? w_auth_str : ""); return (write_message (connptr->client_fd, headers, - code, message, PACKAGE, VERSION, - add)); + code, message, PACKAGE, VERSION, add)); } /* @@ -207,12 +203,12 @@ int send_http_error_message (struct conn_s *connptr) error_file = get_html_file (connptr->error_number); if (!(infile = fopen (error_file, "r"))) { - char *detail = lookup_variable (connptr->error_variables, "detail"); - return (write_message (connptr->client_fd, fallback_error, - connptr->error_number, - connptr->error_string, - connptr->error_string, - detail, PACKAGE, VERSION)); + char *detail = + lookup_variable (connptr->error_variables, "detail"); + return (write_message + (connptr->client_fd, fallback_error, + connptr->error_number, connptr->error_string, + connptr->error_string, detail, PACKAGE, VERSION)); } ret = send_html_file (infile, connptr); @@ -274,8 +270,7 @@ int add_standard_vars (struct conn_s *connptr) gmtime (&global_time)); add_error_variable (connptr, "date", timebuf); - add_error_variable (connptr, "website", - "https://tinyproxy.github.io/"); + add_error_variable (connptr, "website", "https://tinyproxy.github.io/"); add_error_variable (connptr, "version", VERSION); add_error_variable (connptr, "package", PACKAGE); diff --git a/src/log.c b/src/log.c index f85d29d..56f14f7 100644 --- a/src/log.c +++ b/src/log.c @@ -63,7 +63,7 @@ static int log_level = LOG_INFO; */ 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. @@ -71,8 +71,8 @@ static unsigned int logging_initialized = FALSE; /* boolean */ int open_log_file (const char *log_file_name) { if (log_file_name == NULL) { - if(config.godaemon == FALSE) - log_file_fd = fileno(stdout); + if (config.godaemon == FALSE) + log_file_fd = fileno (stdout); else log_file_fd = -1; } else { @@ -86,7 +86,7 @@ int open_log_file (const char *log_file_name) */ 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; } @@ -161,7 +161,7 @@ void log_message (int level, const char *fmt, ...) goto out; } - if(!config.syslog && log_file_fd == -1) + if (!config.syslog && log_file_fd == -1) goto out; 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' * be added next. */ - p = str + strlen(str); - vsnprintf (p, STRING_LENGTH - strlen(str) - 1, fmt, args); + p = str + strlen (str); + vsnprintf (p, STRING_LENGTH - strlen (str) - 1, fmt, args); - p = str + strlen(str); + p = str + strlen (str); *p = '\n'; - *(p+1) = '\0'; + *(p + 1) = '\0'; assert (log_file_fd >= 0); @@ -200,11 +200,11 @@ void log_message (int level, const char *fmt, ...) if (ret == -1) { config.syslog = TRUE; - log_message(LOG_CRIT, "ERROR: Could not write to log " - "file %s: %s.", - config.logf_name, strerror(errno)); - log_message(LOG_CRIT, - "Falling back to syslog logging"); + log_message (LOG_CRIT, "ERROR: Could not write to log " + "file %s: %s.", + config.logf_name, strerror (errno)); + log_message (LOG_CRIT, + "Falling back to syslog logging"); } fsync (log_file_fd); @@ -227,7 +227,7 @@ static void send_stored_logs (void) if (log_message_storage == NULL) 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) { string = @@ -252,7 +252,7 @@ static void send_stored_logs (void) vector_delete (log_message_storage); log_message_storage = NULL; - log_message(LOG_DEBUG, "done sending stored logs"); + log_message (LOG_DEBUG, "done sending stored logs"); } /** diff --git a/src/log.h b/src/log.h index 76bfe6b..9f6f4ec 100644 --- a/src/log.h +++ b/src/log.h @@ -24,7 +24,7 @@ #define TINYPROXY_LOG_H #ifdef HAVE_CONFIG_H -# include +#include #endif /* @@ -92,13 +92,13 @@ * DEBUG2("There was a big problem: %s in connptr %p", "hello", connptr); */ #ifndef NDEBUG -# define DEBUG1(x) \ +#define DEBUG1(x) \ 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) #else -# define DEBUG1(x) do { } while(0) -# define DEBUG2(x, y...) do { } while(0) +#define DEBUG1(x) do { } while(0) +#define DEBUG2(x, y...) do { } while(0) #endif extern int open_log_file (const char *file); diff --git a/src/main.c b/src/main.c index 43170c5..29fbf5f 100644 --- a/src/main.c +++ b/src/main.c @@ -54,8 +54,7 @@ unsigned int received_sighup = FALSE; /* boolean */ /* * Handle a signal */ -static void -takesig (int sig) +static void takesig (int sig) { pid_t pid; int status; @@ -80,8 +79,7 @@ takesig (int sig) /* * Display the version information for the user. */ -static void -display_version (void) +static void display_version (void) { printf ("%s %s\n", PACKAGE, VERSION); } @@ -89,8 +87,7 @@ display_version (void) /* * Display usage to the user. */ -static void -display_usage (void) +static void display_usage (void) { int features = 0; @@ -143,8 +140,7 @@ display_usage (void) ".\n"); } -static int -get_id (char *str) +static int get_id (char *str) { char *tstr; @@ -168,8 +164,7 @@ get_id (char *str) * * This function parses command line arguments. **/ -static void -process_cmdline (int argc, char **argv, struct config_s *conf) +static void process_cmdline (int argc, char **argv, struct config_s *conf) { 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 * initialization when the effective user is root. **/ -static void -change_user (const char *program) +static void change_user (const char *program) { if (config.group && strlen (config.group) > 0) { int gid = get_id (config.group); @@ -240,7 +234,6 @@ change_user (const char *program) program, config.group); exit (EX_NOPERM); } - #ifdef HAVE_SETGROUPS /* Drop all supplementary groups, otherwise these are inherited from the calling process */ if (setgroups (0, NULL) < 0) { @@ -285,7 +278,7 @@ change_user (const char *program) 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"); if (!conf->config_file) { @@ -300,6 +293,9 @@ static void initialize_config_defaults (struct config_s *conf) conf->errorpages = NULL; conf->stathost = safestrdup (TINYPROXY_STATHOST); conf->idletimeout = MAX_IDLE_TIME; +#ifdef UPSTREAM_SUPPORT + conf->deadtime = MAX_DEAD_TIME; +#endif conf->logf_name = NULL; conf->pidpath = NULL; } @@ -326,8 +322,7 @@ done: return ret; } -int -main (int argc, char **argv) +int main (int argc, char **argv) { /* Only allow u+rw bits. This may be required for some versions * 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 " ..."); - if (config_compile_regex()) { + if (config_compile_regex ()) { exit (EX_SOFTWARE); } @@ -344,8 +339,7 @@ main (int argc, char **argv) process_cmdline (argc, argv, &config_defaults); if (reload_config_file (config_defaults.config_file, - &config, - &config_defaults)) { + &config, &config_defaults)) { exit (EX_SOFTWARE); } @@ -362,8 +356,8 @@ main (int argc, char **argv) if (config.godaemon == TRUE) { if (!config.syslog && config.logf_name == NULL) - fprintf(stderr, "WARNING: logging deactivated " - "(can't log to stdout when daemonized)\n"); + fprintf (stderr, "WARNING: logging deactivated " + "(can't log to stdout when daemonized)\n"); makedaemon (); } @@ -373,14 +367,13 @@ main (int argc, char **argv) argv[0]); exit (EX_OSERR); } - #ifdef FILTER_ENABLE if (config.filter) filter_init (); #endif /* FILTER_ENABLE */ /* 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", argv[0]); exit (EX_OSERR); @@ -451,12 +444,13 @@ main (int argc, char **argv) "Could not remove PID file \"%s\": %s.", config.pidpath, strerror (errno)); } - #ifdef FILTER_ENABLE if (config.filter) filter_destroy (); #endif /* FILTER_ENABLE */ + free_config (&config); + shutdown_logging (); return EXIT_SUCCESS; diff --git a/src/main.h b/src/main.h index ca2ee4b..850bba7 100644 --- a/src/main.h +++ b/src/main.h @@ -27,6 +27,9 @@ /* Global variables for the main controls of the program */ #define MAXBUFFSIZE ((size_t)(1024 * 96)) /* Max size of buffer */ #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 */ extern struct config_s config; diff --git a/src/network.c b/src/network.c index 224f924..84c7fb3 100644 --- a/src/network.c +++ b/src/network.c @@ -36,7 +36,7 @@ ssize_t safe_write (int fd, const void *buf, size_t count) { ssize_t len; size_t bytestosend; - const char *buffer = buf; + const char *buffer = buf; assert (fd >= 0); assert (buffer != NULL); @@ -204,8 +204,7 @@ ssize_t readline (int fd, char **whole_buffer) break; } - line_ptr->next = - (struct read_lines_s *) + line_ptr->next = (struct read_lines_s *) safecalloc (sizeof (struct read_lines_s), 1); if (!line_ptr->next) { ret = -ENOMEM; diff --git a/src/reqs.c b/src/reqs.c index 88c0a1c..f5a212a 100644 --- a/src/reqs.c +++ b/src/reqs.c @@ -1417,12 +1417,13 @@ connect_to_upstream (struct conn_s *connptr, struct request_s *request) */ return -1; #else + struct upstream_proxy_list *upp; char *combined_string; int len; struct upstream *cur_upstream = connptr->upstream_proxy; - if (!cur_upstream) { + if (!cur_upstream || !cur_upstream->plist) { log_message (LOG_WARNING, "No upstream proxy defined for %s.", request->host); @@ -1431,11 +1432,39 @@ connect_to_upstream (struct conn_s *connptr, struct request_s *request) return -1; } - connptr->server_fd = - opensock (cur_upstream->host, cur_upstream->port, - connptr->server_ip_addr); + upp = cur_upstream->plist; + while (upp) { + 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, "Could not connect to upstream proxy."); indicate_http_error (connptr, 404, diff --git a/src/reverse-proxy.c b/src/reverse-proxy.c index 0264787..30bfbc5 100644 --- a/src/reverse-proxy.c +++ b/src/reverse-proxy.c @@ -139,13 +139,10 @@ char *reverse_rewrite_url (struct conn_s *connptr, hashmap_t hashofheaders, && (reverse = reversepath_get (cookieval + strlen (REVERSE_COOKIE) + 1, - config.reversepath_list))) - { + config.reversepath_list))) { rewrite_url = (char *) safemalloc - (strlen (url) + - strlen (reverse->url) + - 1); + (strlen (url) + strlen (reverse->url) + 1); strcpy (rewrite_url, reverse->url); strcat (rewrite_url, url + 1); diff --git a/src/sock.c b/src/sock.c index 59c2fa8..e3acb74 100644 --- a/src/sock.c +++ b/src/sock.c @@ -37,7 +37,7 @@ /* * 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) return strerror (errno); @@ -50,8 +50,7 @@ static const char * get_gai_error (int n) * returned if the bind succeeded. Otherwise, -1 is returned * to indicate an error. */ -static int -bind_socket (int sockfd, const char *addr, int family) +static int bind_socket (int sockfd, const char *addr, int family) { struct addrinfo hints, *res, *ressave; int n; @@ -67,7 +66,8 @@ bind_socket (int sockfd, const char *addr, int family) n = getaddrinfo (addr, NULL, &hints, &res); if (n != 0) { 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; } @@ -100,8 +100,8 @@ int opensock (const char *host, int port, const char *bind_to) assert (host != NULL); assert (port > 0); - log_message(LOG_INFO, - "opensock: opening connection to %s:%d", host, port); + log_message (LOG_INFO, + "opensock: opening connection to %s:%d", host, port); memset (&hints, 0, sizeof (struct addrinfo)); 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); if (n != 0) { 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; } - log_message(LOG_INFO, - "opensock: getaddrinfo returned for %s:%d", host, port); + log_message (LOG_INFO, + "opensock: getaddrinfo returned for %s:%d", host, port); ressave = res; do { @@ -128,8 +129,7 @@ int opensock (const char *host, int port, const char *bind_to) /* Bind to the specified address */ if (bind_to) { - if (bind_socket (sockfd, bind_to, - res->ai_family) < 0) { + if (bind_socket (sockfd, bind_to, res->ai_family) < 0) { close (sockfd); 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) { log_message (LOG_ERR, "opensock: Could not establish a connection to %s:%d", - host, - port); + host, port); return -1; } @@ -185,14 +184,13 @@ int socket_blocking (int sock) return fcntl (sock, F_SETFL, flags & ~O_NONBLOCK); } - /** * Try to listen on one socket based on the addrinfo * as returned from getaddrinfo. * * 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 ret; @@ -200,59 +198,60 @@ static int listen_on_one_socket(struct addrinfo *ad) char numerichost[NI_MAXHOST]; int flags = NI_NUMERICHOST; - ret = getnameinfo(ad->ai_addr, ad->ai_addrlen, - numerichost, NI_MAXHOST, NULL, 0, flags); + ret = getnameinfo (ad->ai_addr, ad->ai_addrlen, + numerichost, NI_MAXHOST, NULL, 0, flags); 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; } - log_message(LOG_INFO, "trying to listen on host[%s], family[%d], " - "socktype[%d], proto[%d]", numerichost, - ad->ai_family, ad->ai_socktype, ad->ai_protocol); + log_message (LOG_INFO, "trying to listen on host[%s], family[%d], " + "socktype[%d], proto[%d]", numerichost, + 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) { - log_message(LOG_ERR, "socket() failed: %s", strerror(errno)); + log_message (LOG_ERR, "socket() failed: %s", strerror (errno)); 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) { - log_message(LOG_ERR, - "setsockopt failed to set SO_REUSEADDR: %s", - strerror(errno)); - close(listenfd); + log_message (LOG_ERR, + "setsockopt failed to set SO_REUSEADDR: %s", + strerror (errno)); + close (listenfd); return -1; } if (ad->ai_family == AF_INET6) { - ret = setsockopt(listenfd, IPPROTO_IPV6, IPV6_V6ONLY, &on, - sizeof(on)); + ret = setsockopt (listenfd, IPPROTO_IPV6, IPV6_V6ONLY, &on, + sizeof (on)); if (ret != 0) { - log_message(LOG_ERR, - "setsockopt failed to set IPV6_V6ONLY: %s", - strerror(errno)); - close(listenfd); + log_message (LOG_ERR, + "setsockopt failed to set IPV6_V6ONLY: %s", + strerror (errno)); + close (listenfd); return -1; } } - ret = bind(listenfd, ad->ai_addr, ad->ai_addrlen); + ret = bind (listenfd, ad->ai_addr, ad->ai_addrlen); if (ret != 0) { - log_message(LOG_ERR, "bind failed: %s", strerror (errno)); - close(listenfd); - return -1; - } - - ret = listen(listenfd, MAXLISTEN); - if (ret != 0) { - log_message(LOG_ERR, "listen failed: %s", strerror(errno)); - close(listenfd); + log_message (LOG_ERR, "bind failed: %s", strerror (errno)); + close (listenfd); 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; } @@ -277,8 +276,8 @@ int listen_sock (const char *addr, uint16_t port, vector_t listen_fds) assert (port > 0); assert (listen_fds != NULL); - log_message(LOG_INFO, "listen_sock called with addr = '%s'", - addr == NULL ? "(NULL)" : addr); + log_message (LOG_INFO, "listen_sock called with addr = '%s'", + addr == NULL ? "(NULL)" : addr); memset (&hints, 0, sizeof (struct addrinfo)); 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) { log_message (LOG_ERR, "Unable to getaddrinfo() for %s:%d because of %s", - addr, - port, - get_gai_error (n)); + addr, port, get_gai_error (n)); return -1; } for (rp = result; rp != NULL; rp = rp->ai_next) { int listenfd; - listenfd = listen_on_one_socket(rp); + listenfd = listen_on_one_socket (rp); if (listenfd == -1) { continue; } - vector_append (listen_fds, &listenfd, sizeof(int)); + vector_append (listen_fds, &listenfd, sizeof (int)); /* success */ ret = 0; diff --git a/src/stats.c b/src/stats.c index c7b4423..2e577b4 100644 --- a/src/stats.c +++ b/src/stats.c @@ -59,8 +59,7 @@ void init_stats (void) /* * Display the statics of the tinyproxy server. */ -int -showstats (struct conn_s *connptr) +int showstats (struct conn_s *connptr) { char *message_buffer; char opens[16], reqs[16], badconns[16], denied[16], refused[16]; @@ -78,32 +77,31 @@ showstats (struct conn_s *connptr) return -1; snprintf - (message_buffer, MAXBUFFSIZE, - "\n" - "\n" - "\n" - "%s version %s run-time statistics\n" - "\n" - "

%s version %s run-time statistics

\n" - "

\n" - "Number of open connections: %lu
\n" - "Number of requests: %lu
\n" - "Number of bad connections: %lu
\n" - "Number of denied connections: %lu
\n" - "Number of refused connections due to high load: %lu\n" - "

\n" - "
\n" - "

Generated by %s version %s.

\n" "\n" - "\n", - PACKAGE, VERSION, PACKAGE, VERSION, - stats->num_open, - stats->num_reqs, - stats->num_badcons, stats->num_denied, - stats->num_refused, PACKAGE, VERSION); + (message_buffer, MAXBUFFSIZE, + "\n" + "\n" + "\n" + "%s version %s run-time statistics\n" + "\n" + "

%s version %s run-time statistics

\n" + "

\n" + "Number of open connections: %lu
\n" + "Number of requests: %lu
\n" + "Number of bad connections: %lu
\n" + "Number of denied connections: %lu
\n" + "Number of refused connections due to high load: %lu\n" + "

\n" + "
\n" + "

Generated by %s version %s.

\n" "\n" + "\n", + PACKAGE, VERSION, PACKAGE, VERSION, + stats->num_open, + stats->num_reqs, + stats->num_badcons, stats->num_denied, + stats->num_refused, PACKAGE, VERSION); - if (send_http_message (connptr, 200, "OK", - message_buffer) < 0) { + if (send_http_message (connptr, 200, "OK", message_buffer) < 0) { safefree (message_buffer); return -1; } diff --git a/src/transparent-proxy.c b/src/transparent-proxy.c index df5fbce..f6e3176 100644 --- a/src/transparent-proxy.c +++ b/src/transparent-proxy.c @@ -111,21 +111,21 @@ do_transparent_proxy (struct conn_s *connptr, hashmap_t hashofheaders, 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; - 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) { - log_message(LOG_ERR, - "transparent: destination IP %s is local " - "on socket fd %d", - request->host, connptr->client_fd); - indicate_http_error(connptr, 400, "Bad Request", - "detail", - "You tried to connect to the " - "machine the proxy is running on", - "url", *url, NULL); + if (addr && strcmp (request->host, addr) == 0) { + log_message (LOG_ERR, + "transparent: destination IP %s is local " + "on socket fd %d", + request->host, connptr->client_fd); + indicate_http_error (connptr, 400, "Bad Request", + "detail", + "You tried to connect to the " + "machine the proxy is running on", + "url", *url, NULL); return 0; } } diff --git a/src/upstream.c b/src/upstream.c index a239c54..9ddaeed 100644 --- a/src/upstream.c +++ b/src/upstream.c @@ -31,6 +31,25 @@ #include "basicauth.h" #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) { 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. */ -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 *pass, proxy_type type) { char *ptr; struct upstream *up; + struct upstream_proxy_list *upp; #ifdef UPSTREAM_REGEX int cflags = REG_NEWLINE | REG_NOSUB; int rflag = 0; @@ -70,7 +117,8 @@ static struct upstream *upstream_build (const char *host, int port, } 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 up->pat = NULL; up->cpat = NULL; @@ -124,18 +172,18 @@ static struct upstream *upstream_build (const char *host, int port, } if (domain == NULL) { - if (!host || host[0] == '\0' || port < 1) { + if (!plist || plist->host[0] == '\0' || plist->port < 1) { log_message (LOG_WARNING, "Nonsense upstream rule: invalid host or port"); goto fail; } - up->host = safestrdup (host); - up->port = port; + up->plist = uplcpy (plist); - log_message (LOG_INFO, "Added upstream %s %s:%d for [default]", - proxy_type_name (type), host, port); - } else if (host == NULL || type == PT_NONE) { + log_message (LOG_INFO, "Added upstream %s %s for [default]", + proxy_type_name (type), + proxy_list_name (up->plist)); + } else if (plist == NULL || type == PT_NONE) { if (!domain || domain[0] == '\0') { log_message (LOG_WARNING, "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); } else { - if (!host || host[0] == '\0' || port < 1 || !domain - || domain[0] == '\0') { + if (!plist || plist->host[0] == '\0' || plist->port < 1 + || !domain || domain[0] == '\0') { log_message (LOG_WARNING, "Nonsense upstream rule: invalid parameters"); goto fail; } - up->host = safestrdup (host); - up->port = port; + up->plist = uplcpy (plist); up->domain = safestrdup (domain); #ifdef UPSTREAM_REGEX if (rflag) { @@ -205,19 +252,29 @@ static struct upstream *upstream_build (const char *host, int port, } } #endif - log_message (LOG_INFO, "Added upstream %s %s:%d for %s", - proxy_type_name (type), host, port, domain); + log_message (LOG_INFO, "Added upstream %s %s for %s", + proxy_type_name (type), + proxy_list_name (up->plist), domain); } return up; fail: safefree (up->ua.user); + safefree (up->ua.authstr); 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); #ifdef UPSTREAM_REGEX safefree (up->pat); + if (up->cpat) + regfree (up->cpat); safefree (up->cpat); #endif safefree (up); @@ -228,13 +285,14 @@ fail: /* * 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, proxy_type type, struct upstream **upstream_list) { 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) { return; } @@ -265,8 +323,23 @@ void upstream_add (const char *host, int port, const char *domain, return; 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->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); return; @@ -323,14 +396,14 @@ struct upstream *upstream_get (struct request_s *request, struct upstream *up) up = up->next; } - - if (up && (!up->host || !up->port)) + if (up && !up->plist) up = NULL; if (up) - log_message (LOG_INFO, "Found upstream proxy %s %s:%d for %s", - proxy_type_name (up->type), up->host, up->port, - host); + log_message (LOG_INFO, + "Found upstream proxy/proxies %s %s for %s", + proxy_type_name (up->type), + proxy_list_name (up->plist), host); else log_message (LOG_INFO, "No upstream proxy for %s", host); @@ -341,9 +414,24 @@ void free_upstream_list (struct upstream *up) { while (up) { struct upstream *tmp = up; + struct upstream_proxy_list *upp = up->plist; up = up->next; + while (upp) { + struct upstream_proxy_list *tmpp = upp; + upp = upp->next; + safefree (tmpp->host); + safefree (tmpp); + } 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); } } diff --git a/src/upstream.h b/src/upstream.h index aa1b039..92652d9 100644 --- a/src/upstream.h +++ b/src/upstream.h @@ -39,16 +39,25 @@ typedef enum proxy_type { PT_SOCKS5 } 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 *next; char *domain; /* optional */ + struct upstream_proxy_list *plist; char *host; + int port; union { char *user; char *authstr; } ua; char *pass; - int port; in_addr_t ip, mask; proxy_type type; #if defined(UPSTREAM_SUPPORT) && defined(UPSTREAM_REGEX) @@ -59,9 +68,10 @@ struct upstream { #ifdef UPSTREAM_SUPPORT 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 void upstream_add (const struct upstream_proxy_list *phost, + const char *domain, const char *user, + const char *pass, proxy_type type, + struct upstream **upstream_list); extern struct upstream *upstream_get (struct request_s *request, struct upstream *up); extern void free_upstream_list (struct upstream *up); diff --git a/src/utils.c b/src/utils.c index ef2e673..bb7ea94 100644 --- a/src/utils.c +++ b/src/utils.c @@ -185,8 +185,7 @@ int create_file_safely (const char *filename, unsigned int truncate_file) * * Returns: %0 on success, non-zero values on errors. **/ -int -pidfile_create (const char *filename) +int pidfile_create (const char *filename) { int fildes; FILE *fd; diff --git a/src/vector.c b/src/vector.c index cf9fc75..18f42c6 100644 --- a/src/vector.c +++ b/src/vector.c @@ -111,10 +111,7 @@ typedef enum { } vector_pos_t; static int -vector_insert (vector_t vector, - void *data, - size_t len, - vector_pos_t pos) +vector_insert (vector_t vector, void *data, size_t len, vector_pos_t pos) { struct vectorentry_s *entry;