Fix proxy list and regex
This commit is contained in:
commit
a9edc77d0c
@ -190,37 +190,11 @@ The possible keywords and their descriptions are as follows:
|
|||||||
|
|
||||||
*MaxClients*::
|
*MaxClients*::
|
||||||
|
|
||||||
Tinyproxy creates one child process for each connected client.
|
Tinyproxy creates one thread for each connected client.
|
||||||
This options specifies the absolute highest number processes that
|
This options specifies the absolute highest number processes that
|
||||||
will be created. With other words, only MaxClients clients can be
|
will be created. With other words, only MaxClients clients can be
|
||||||
connected to Tinyproxy simultaneously.
|
connected to Tinyproxy simultaneously.
|
||||||
|
|
||||||
*MinSpareServers*::
|
|
||||||
*MaxSpareServers*::
|
|
||||||
|
|
||||||
Tinyproxy always keeps a certain number of idle child processes
|
|
||||||
so that it can handle new incoming client requests quickly.
|
|
||||||
`MinSpareServer` and `MaxSpareServers` control the lower and upper
|
|
||||||
limits for the number of spare processes. I.e. when the number of
|
|
||||||
spare servers drops below `MinSpareServers` then Tinyproxy will
|
|
||||||
start forking new spare processes in the background and when the
|
|
||||||
number of spare processes exceeds `MaxSpareServers` then Tinyproxy
|
|
||||||
will kill off extra processes.
|
|
||||||
|
|
||||||
*StartServers*::
|
|
||||||
|
|
||||||
The number of servers to start initially. This should usually be
|
|
||||||
set to a value between MinSpareServers and MaxSpareServers.
|
|
||||||
|
|
||||||
*MaxRequestsPerChild*::
|
|
||||||
|
|
||||||
This limits the number of connections that a child process
|
|
||||||
will handle before it is killed. The default value is `0`
|
|
||||||
which disables this feature. This option is meant as an
|
|
||||||
emergency measure in the case of problems with memory leakage.
|
|
||||||
In that case, setting `MaxRequestsPerChild` to a value of e.g.
|
|
||||||
1000, or 10000 can be useful.
|
|
||||||
|
|
||||||
*Allow*::
|
*Allow*::
|
||||||
*Deny*::
|
*Deny*::
|
||||||
|
|
||||||
@ -236,6 +210,9 @@ The possible keywords and their descriptions are as follows:
|
|||||||
end of the client host name, i.e, this can be a full host name
|
end of the client host name, i.e, this can be a full host name
|
||||||
like `host.example.com` or a domain name like `.example.com` or
|
like `host.example.com` or a domain name like `.example.com` or
|
||||||
even a top level domain name like `.com`.
|
even a top level domain name like `.com`.
|
||||||
|
Note that by adding a rule using a host or domain name, a costly name
|
||||||
|
lookup has to be done for every new connection, which could slow down
|
||||||
|
the service considerably.
|
||||||
|
|
||||||
*AddHeader*::
|
*AddHeader*::
|
||||||
|
|
||||||
|
@ -189,30 +189,6 @@ LogLevel Info
|
|||||||
#
|
#
|
||||||
MaxClients 100
|
MaxClients 100
|
||||||
|
|
||||||
#
|
|
||||||
# MinSpareServers/MaxSpareServers: These settings set the upper and
|
|
||||||
# lower limit for the number of spare servers which should be available.
|
|
||||||
#
|
|
||||||
# If the number of spare servers falls below MinSpareServers then new
|
|
||||||
# server processes will be spawned. If the number of servers exceeds
|
|
||||||
# MaxSpareServers then the extras will be killed off.
|
|
||||||
#
|
|
||||||
MinSpareServers 5
|
|
||||||
MaxSpareServers 20
|
|
||||||
|
|
||||||
#
|
|
||||||
# StartServers: The number of servers to start initially.
|
|
||||||
#
|
|
||||||
StartServers 10
|
|
||||||
|
|
||||||
#
|
|
||||||
# MaxRequestsPerChild: The number of connections a thread will handle
|
|
||||||
# before it is killed. In practise this should be set to 0, which
|
|
||||||
# disables thread reaping. If you do notice problems with memory
|
|
||||||
# leakage, then set this to something like 10000.
|
|
||||||
#
|
|
||||||
MaxRequestsPerChild 0
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Allow: Customization of authorization controls. If there are any
|
# Allow: Customization of authorization controls. If there are any
|
||||||
# access control keywords then the default action is to DENY. Otherwise,
|
# access control keywords then the default action is to DENY. Otherwise,
|
||||||
|
@ -48,10 +48,12 @@ tinyproxy_SOURCES = \
|
|||||||
upstream.c upstream.h \
|
upstream.c upstream.h \
|
||||||
basicauth.c basicauth.h \
|
basicauth.c basicauth.h \
|
||||||
base64.c base64.h \
|
base64.c base64.h \
|
||||||
|
sblist.c sblist.h \
|
||||||
|
loop.c loop.h \
|
||||||
connect-ports.c connect-ports.h
|
connect-ports.c connect-ports.h
|
||||||
|
|
||||||
EXTRA_tinyproxy_SOURCES = filter.c filter.h \
|
EXTRA_tinyproxy_SOURCES = filter.c filter.h \
|
||||||
reverse-proxy.c reverse-proxy.h \
|
reverse-proxy.c reverse-proxy.h \
|
||||||
transparent-proxy.c transparent-proxy.h
|
transparent-proxy.c transparent-proxy.h
|
||||||
tinyproxy_DEPENDENCIES = @ADDITIONAL_OBJECTS@
|
tinyproxy_DEPENDENCIES = @ADDITIONAL_OBJECTS@
|
||||||
tinyproxy_LDADD = @ADDITIONAL_OBJECTS@
|
tinyproxy_LDADD = @ADDITIONAL_OBJECTS@ -lpthread
|
||||||
|
38
src/acl.c
38
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.
|
* 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;
|
||||||
@ -221,8 +221,8 @@ insert_acl (char *location, acl_access_t access_type, vector_t *access_list)
|
|||||||
* -1 if no tests match, so skip
|
* -1 if no tests match, so skip
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
acl_string_processing (struct acl_s *acl,
|
acl_string_processing (struct acl_s *acl, const char *ip_address,
|
||||||
const char *ip_address, const char *string_address)
|
union sockaddr_union *addr, char *string_addr)
|
||||||
{
|
{
|
||||||
int match;
|
int match;
|
||||||
struct addrinfo hints, *res, *ressave;
|
struct addrinfo hints, *res, *ressave;
|
||||||
@ -231,7 +231,6 @@ acl_string_processing (struct acl_s *acl,
|
|||||||
|
|
||||||
assert (acl && acl->type == ACL_STRING);
|
assert (acl && acl->type == ACL_STRING);
|
||||||
assert (ip_address && strlen (ip_address) > 0);
|
assert (ip_address && strlen (ip_address) > 0);
|
||||||
assert (string_address && strlen (string_address) > 0);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the first character of the ACL string is a period, we need to
|
* If the first character of the ACL string is a period, we need to
|
||||||
@ -267,7 +266,15 @@ acl_string_processing (struct acl_s *acl,
|
|||||||
}
|
}
|
||||||
|
|
||||||
STRING_TEST:
|
STRING_TEST:
|
||||||
test_length = strlen (string_address);
|
if(string_addr[0] == 0) {
|
||||||
|
/* only do costly hostname resolution when it is absolutely needed,
|
||||||
|
and only once */
|
||||||
|
if(getnameinfo ((void *) addr, sizeof (*addr),
|
||||||
|
string_addr, HOSTNAME_LENGTH, NULL, 0, 0) != 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
test_length = strlen (string_addr);
|
||||||
match_length = strlen (acl->address.string);
|
match_length = strlen (acl->address.string);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -278,7 +285,7 @@ STRING_TEST:
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (strcasecmp
|
if (strcasecmp
|
||||||
(string_address + (test_length - match_length),
|
(string_addr + (test_length - match_length),
|
||||||
acl->address.string) == 0) {
|
acl->address.string) == 0) {
|
||||||
if (acl->access == ACL_DENY)
|
if (acl->access == ACL_DENY)
|
||||||
return 0;
|
return 0;
|
||||||
@ -329,15 +336,18 @@ static int check_numeric_acl (const struct acl_s *acl, const char *ip)
|
|||||||
* 1 if allowed
|
* 1 if allowed
|
||||||
* 0 if denied
|
* 0 if denied
|
||||||
*/
|
*/
|
||||||
int check_acl (const char *ip, const char *host, vector_t access_list)
|
int check_acl (const char *ip, union sockaddr_union *addr, vector_t access_list)
|
||||||
{
|
{
|
||||||
struct acl_s *acl;
|
struct acl_s *acl;
|
||||||
int perm = 0;
|
int perm = 0;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
char string_addr[HOSTNAME_LENGTH];
|
||||||
|
|
||||||
assert (ip != NULL);
|
assert (ip != NULL);
|
||||||
assert (host != NULL);
|
assert (host != NULL);
|
||||||
|
|
||||||
|
string_addr[0] = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there is no access list allow everything.
|
* If there is no access list allow everything.
|
||||||
*/
|
*/
|
||||||
@ -348,7 +358,7 @@ int check_acl (const char *ip, const char *host, vector_t access_list)
|
|||||||
acl = (struct acl_s *) vector_getentry (access_list, i, NULL);
|
acl = (struct acl_s *) vector_getentry (access_list, i, NULL);
|
||||||
switch (acl->type) {
|
switch (acl->type) {
|
||||||
case ACL_STRING:
|
case ACL_STRING:
|
||||||
perm = acl_string_processing (acl, ip, host);
|
perm = acl_string_processing (acl, ip, addr, string_addr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACL_NUMERIC:
|
case ACL_NUMERIC:
|
||||||
@ -371,8 +381,8 @@ int check_acl (const char *ip, const char *host, vector_t access_list)
|
|||||||
/*
|
/*
|
||||||
* Deny all connections by default.
|
* Deny all connections by default.
|
||||||
*/
|
*/
|
||||||
log_message (LOG_NOTICE, "Unauthorized connection from \"%s\" [%s].",
|
log_message (LOG_NOTICE, "Unauthorized connection from \"%s\".",
|
||||||
host, ip);
|
ip);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,12 +22,13 @@
|
|||||||
#define TINYPROXY_ACL_H
|
#define TINYPROXY_ACL_H
|
||||||
|
|
||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
|
#include "sock.h"
|
||||||
|
|
||||||
typedef enum { ACL_ALLOW, ACL_DENY } acl_access_t;
|
typedef enum { ACL_ALLOW, ACL_DENY } acl_access_t;
|
||||||
|
|
||||||
extern int insert_acl (char *location, acl_access_t access_type,
|
extern int insert_acl (char *location, acl_access_t access_type,
|
||||||
vector_t *access_list);
|
vector_t *access_list);
|
||||||
extern int check_acl (const char *ip_address, const char *string_address,
|
extern int check_acl (const char *ip_address, union sockaddr_union *addr,
|
||||||
vector_t access_list);
|
vector_t access_list);
|
||||||
extern void flush_access_list (vector_t access_list);
|
extern void flush_access_list (vector_t access_list);
|
||||||
|
|
||||||
|
53
src/base64.c
53
src/base64.c
@ -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,30 +27,31 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,31 +32,29 @@
|
|||||||
* -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)
|
if (!user || !pass) return -1;
|
||||||
return -1;
|
l = snprintf(tmp, sizeof tmp, "%s:%s", user, pass);
|
||||||
l = snprintf (tmp, sizeof tmp, "%s:%s", user, pass);
|
if (l < 0 || l >= (ssize_t) sizeof tmp) return 0;
|
||||||
if (l < 0 || l >= (ssize_t) sizeof tmp)
|
if (bufsize < (BASE64ENC_BYTES((unsigned)l) + 1)) return 0;
|
||||||
return 0;
|
base64enc(buf, tmp, l);
|
||||||
if (bufsize < (BASE64ENC_BYTES ((unsigned) l) + 1))
|
return BASE64ENC_BYTES(l);
|
||||||
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, 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];
|
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");
|
||||||
@ -67,13 +65,14 @@ void basicauth_add (vector_t authlist, const char *user, const char *pass)
|
|||||||
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, "Added basic auth user : %s", user);
|
log_message (LOG_INFO,
|
||||||
|
"Added basic auth user : %s", user);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -85,16 +84,15 @@ 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)
|
if (vl == -EINVAL) return 0;
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
10
src/buffer.c
10
src/buffer.c
@ -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;
|
||||||
|
655
src/child.c
655
src/child.c
@ -31,176 +31,64 @@
|
|||||||
#include "sock.h"
|
#include "sock.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
#include "sblist.h"
|
||||||
|
#include "loop.h"
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
static vector_t listen_fds;
|
static vector_t listen_fds;
|
||||||
|
|
||||||
/*
|
struct client {
|
||||||
* Stores the internal data needed for each child (connection)
|
union sockaddr_union addr;
|
||||||
*/
|
int fd;
|
||||||
enum child_status_t { T_EMPTY, T_WAITING, T_CONNECTED };
|
|
||||||
struct child_s {
|
|
||||||
pid_t tid;
|
|
||||||
unsigned int connects;
|
|
||||||
enum child_status_t status;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
struct child {
|
||||||
* A pointer to an array of children. A certain number of children are
|
pthread_t thread;
|
||||||
* created when the program is started.
|
struct client client;
|
||||||
*/
|
volatile int done;
|
||||||
static struct child_s *child_ptr;
|
};
|
||||||
|
|
||||||
static struct child_config_s {
|
static void* child_thread(void* data)
|
||||||
unsigned int maxclients, maxrequestsperchild;
|
|
||||||
unsigned int maxspareservers, minspareservers, startservers;
|
|
||||||
} child_config;
|
|
||||||
|
|
||||||
static unsigned int *servers_waiting; /* servers waiting for a connection */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Lock/Unlock the "servers_waiting" variable so that two children cannot
|
|
||||||
* modify it at the same time.
|
|
||||||
*/
|
|
||||||
#define SERVER_COUNT_LOCK() _child_lock_wait()
|
|
||||||
#define SERVER_COUNT_UNLOCK() _child_lock_release()
|
|
||||||
|
|
||||||
/* START OF LOCKING SECTION */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* These variables are required for the locking mechanism. Also included
|
|
||||||
* are the "private" functions for locking/unlocking.
|
|
||||||
*/
|
|
||||||
static struct flock lock_it, unlock_it;
|
|
||||||
static int lock_fd = -1;
|
|
||||||
|
|
||||||
static void _child_lock_init (void)
|
|
||||||
{
|
{
|
||||||
char lock_file[] = "/tmp/tinyproxy.servers.lock.XXXXXX";
|
struct child *c = data;
|
||||||
|
handle_connection (c->client.fd, &c->client.addr);
|
||||||
/* Only allow u+rw bits. This may be required for some versions
|
c->done = 1;
|
||||||
* of glibc so that mkstemp() doesn't make us vulnerable.
|
return NULL;
|
||||||
*/
|
|
||||||
umask (0177);
|
|
||||||
|
|
||||||
lock_fd = mkstemp (lock_file);
|
|
||||||
unlink (lock_file);
|
|
||||||
|
|
||||||
lock_it.l_type = F_WRLCK;
|
|
||||||
lock_it.l_whence = SEEK_SET;
|
|
||||||
lock_it.l_start = 0;
|
|
||||||
lock_it.l_len = 0;
|
|
||||||
|
|
||||||
unlock_it.l_type = F_UNLCK;
|
|
||||||
unlock_it.l_whence = SEEK_SET;
|
|
||||||
unlock_it.l_start = 0;
|
|
||||||
unlock_it.l_len = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _child_lock_wait (void)
|
static sblist *childs;
|
||||||
|
|
||||||
|
static void collect_threads(void)
|
||||||
{
|
{
|
||||||
int rc;
|
size_t i;
|
||||||
|
for (i = 0; i < sblist_getsize(childs); ) {
|
||||||
while ((rc = fcntl (lock_fd, F_SETLKW, &lock_it)) < 0) {
|
struct child *c = *((struct child**)sblist_get(childs, i));
|
||||||
if (errno == EINTR)
|
if (c->done) {
|
||||||
continue;
|
pthread_join(c->thread, 0);
|
||||||
else
|
sblist_delete(childs, i);
|
||||||
return;
|
safefree(c);
|
||||||
}
|
} else i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _child_lock_release (void)
|
|
||||||
{
|
|
||||||
if (fcntl (lock_fd, F_SETLKW, &unlock_it) < 0)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* END OF LOCKING SECTION */
|
|
||||||
|
|
||||||
#define SERVER_INC() do { \
|
|
||||||
SERVER_COUNT_LOCK(); \
|
|
||||||
++(*servers_waiting); \
|
|
||||||
DEBUG2("INC: servers_waiting: %d", *servers_waiting); \
|
|
||||||
SERVER_COUNT_UNLOCK(); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define SERVER_DEC() do { \
|
|
||||||
SERVER_COUNT_LOCK(); \
|
|
||||||
assert(*servers_waiting > 0); \
|
|
||||||
--(*servers_waiting); \
|
|
||||||
DEBUG2("DEC: servers_waiting: %d", *servers_waiting); \
|
|
||||||
SERVER_COUNT_UNLOCK(); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set the configuration values for the various child related settings.
|
|
||||||
*/
|
|
||||||
short int child_configure (child_config_t type, unsigned int val)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case CHILD_MAXCLIENTS:
|
|
||||||
child_config.maxclients = val;
|
|
||||||
break;
|
|
||||||
case CHILD_MAXSPARESERVERS:
|
|
||||||
child_config.maxspareservers = val;
|
|
||||||
break;
|
|
||||||
case CHILD_MINSPARESERVERS:
|
|
||||||
child_config.minspareservers = val;
|
|
||||||
break;
|
|
||||||
case CHILD_STARTSERVERS:
|
|
||||||
child_config.startservers = val;
|
|
||||||
break;
|
|
||||||
case CHILD_MAXREQUESTSPERCHILD:
|
|
||||||
child_config.maxrequestsperchild = val;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
DEBUG2 ("Invalid type (%d)", type);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* child signal handler for sighup
|
|
||||||
*/
|
|
||||||
static void child_sighup_handler (int sig)
|
|
||||||
{
|
|
||||||
if (sig == SIGHUP) {
|
|
||||||
/*
|
|
||||||
* Ignore the return value of reload_config for now.
|
|
||||||
* This should actually be handled somehow...
|
|
||||||
*/
|
|
||||||
reload_config ();
|
|
||||||
|
|
||||||
#ifdef FILTER_ENABLE
|
|
||||||
filter_reload ();
|
|
||||||
#endif /* FILTER_ENABLE */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the main (per child) loop.
|
* This is the main loop accepting new connections.
|
||||||
*/
|
*/
|
||||||
static void child_main (struct child_s *ptr)
|
void child_main_loop (void)
|
||||||
{
|
{
|
||||||
int connfd;
|
int connfd;
|
||||||
struct sockaddr *cliaddr;
|
union sockaddr_union cliaddr_storage;
|
||||||
socklen_t clilen;
|
struct sockaddr *cliaddr = (void*) &cliaddr_storage;
|
||||||
|
socklen_t clilen = sizeof(cliaddr_storage);
|
||||||
fd_set rfds;
|
fd_set rfds;
|
||||||
int maxfd = 0;
|
|
||||||
ssize_t i;
|
ssize_t i;
|
||||||
int ret;
|
int ret, listenfd, maxfd, was_full = 0;
|
||||||
|
pthread_attr_t *attrp, attr;
|
||||||
|
struct child *child;
|
||||||
|
|
||||||
cliaddr = (struct sockaddr *)
|
childs = sblist_new(sizeof (struct child*), config.maxclients);
|
||||||
safemalloc (sizeof (struct sockaddr_storage));
|
|
||||||
if (!cliaddr) {
|
|
||||||
log_message (LOG_CRIT,
|
|
||||||
"Could not allocate memory for child address.");
|
|
||||||
exit (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr->connects = 0;
|
loop_records_init();
|
||||||
srand (time (NULL));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have to wait for connections on multiple fds,
|
* We have to wait for connections on multiple fds,
|
||||||
@ -208,304 +96,21 @@ static void child_main (struct child_s *ptr)
|
|||||||
*/
|
*/
|
||||||
while (!config.quit) {
|
while (!config.quit) {
|
||||||
|
|
||||||
int listenfd = -1;
|
collect_threads();
|
||||||
|
|
||||||
FD_ZERO (&rfds);
|
if (sblist_getsize(childs) >= config.maxclients) {
|
||||||
|
if (!was_full)
|
||||||
for (i = 0; i < vector_length (listen_fds); i++) {
|
|
||||||
int *fd = (int *) vector_getentry (listen_fds, i, NULL);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
FD_SET (*fd, &rfds);
|
|
||||||
maxfd = max (maxfd, *fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr->status = T_WAITING;
|
|
||||||
|
|
||||||
clilen = sizeof (struct sockaddr_storage);
|
|
||||||
|
|
||||||
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);
|
|
||||||
} 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);
|
|
||||||
|
|
||||||
if (FD_ISSET (*fd, &rfds)) {
|
|
||||||
/*
|
|
||||||
* only accept the connection on the first
|
|
||||||
* fd that we find readable. - fair?
|
|
||||||
*/
|
|
||||||
listenfd = *fd;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (listenfd == -1) {
|
|
||||||
log_message (LOG_WARNING, "Strange: None of our listen "
|
|
||||||
"fds was readable after select");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We have a socket that is readable.
|
|
||||||
* Continue handling this connection.
|
|
||||||
*/
|
|
||||||
|
|
||||||
connfd = accept (listenfd, cliaddr, &clilen);
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
/*
|
|
||||||
* Enable the TINYPROXY_DEBUG environment variable if you
|
|
||||||
* want to use the GDB debugger.
|
|
||||||
*/
|
|
||||||
if (getenv ("TINYPROXY_DEBUG")) {
|
|
||||||
/* Pause for 10 seconds to allow us to connect debugger */
|
|
||||||
fprintf (stderr,
|
|
||||||
"Process has accepted connection: %ld\n",
|
|
||||||
(long int) ptr->tid);
|
|
||||||
sleep (10);
|
|
||||||
fprintf (stderr, "Continuing process: %ld\n",
|
|
||||||
(long int) ptr->tid);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make sure no error occurred...
|
|
||||||
*/
|
|
||||||
if (connfd < 0) {
|
|
||||||
log_message (LOG_ERR,
|
|
||||||
"Accept returned an error (%s) ... retrying.",
|
|
||||||
strerror (errno));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr->status = T_CONNECTED;
|
|
||||||
|
|
||||||
SERVER_DEC ();
|
|
||||||
|
|
||||||
handle_connection (connfd);
|
|
||||||
ptr->connects++;
|
|
||||||
|
|
||||||
if (child_config.maxrequestsperchild != 0) {
|
|
||||||
DEBUG2 ("%u connections so far...", ptr->connects);
|
|
||||||
|
|
||||||
if (ptr->connects == child_config.maxrequestsperchild) {
|
|
||||||
log_message (LOG_NOTICE,
|
log_message (LOG_NOTICE,
|
||||||
"Child has reached MaxRequestsPerChild (%u). "
|
"Maximum number of connections reached. "
|
||||||
"Killing child.", ptr->connects);
|
"Refusing new connections.");
|
||||||
break;
|
was_full = 1;
|
||||||
}
|
usleep(16);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SERVER_COUNT_LOCK ();
|
was_full = 0;
|
||||||
if (*servers_waiting > child_config.maxspareservers) {
|
listenfd = -1;
|
||||||
/*
|
maxfd = 0;
|
||||||
* There are too many spare children, kill ourself
|
|
||||||
* off.
|
|
||||||
*/
|
|
||||||
log_message (LOG_NOTICE,
|
|
||||||
"Waiting servers (%d) exceeds MaxSpareServers (%d). "
|
|
||||||
"Killing child.",
|
|
||||||
*servers_waiting,
|
|
||||||
child_config.maxspareservers);
|
|
||||||
SERVER_COUNT_UNLOCK ();
|
|
||||||
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
SERVER_COUNT_UNLOCK ();
|
|
||||||
}
|
|
||||||
|
|
||||||
SERVER_INC ();
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr->status = T_EMPTY;
|
|
||||||
|
|
||||||
safefree (cliaddr);
|
|
||||||
exit (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Fork a child "child" (or in our case a process) and then start up the
|
|
||||||
* child_main() function.
|
|
||||||
*/
|
|
||||||
static pid_t child_make (struct child_s *ptr)
|
|
||||||
{
|
|
||||||
pid_t pid;
|
|
||||||
|
|
||||||
if ((pid = fork ()) > 0)
|
|
||||||
return pid; /* parent */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reset the SIGNALS so that the child can be reaped.
|
|
||||||
*/
|
|
||||||
set_signal_handler (SIGCHLD, SIG_DFL);
|
|
||||||
set_signal_handler (SIGTERM, SIG_DFL);
|
|
||||||
set_signal_handler (SIGHUP, child_sighup_handler);
|
|
||||||
|
|
||||||
child_main (ptr); /* never returns */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create a pool of children to handle incoming connections
|
|
||||||
*/
|
|
||||||
short int child_pool_create (void)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make sure the number of MaxClients is not zero, since this
|
|
||||||
* variable determines the size of the array created for children
|
|
||||||
* later on.
|
|
||||||
*/
|
|
||||||
if (child_config.maxclients == 0) {
|
|
||||||
log_message (LOG_ERR,
|
|
||||||
"child_pool_create: \"MaxClients\" must be "
|
|
||||||
"greater than zero.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (child_config.startservers == 0) {
|
|
||||||
log_message (LOG_ERR,
|
|
||||||
"child_pool_create: \"StartServers\" must be "
|
|
||||||
"greater than zero.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
child_ptr =
|
|
||||||
(struct child_s *) calloc_shared_memory (child_config.maxclients,
|
|
||||||
sizeof (struct child_s));
|
|
||||||
if (!child_ptr) {
|
|
||||||
log_message (LOG_ERR,
|
|
||||||
"Could not allocate memory for children.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
servers_waiting =
|
|
||||||
(unsigned int *) malloc_shared_memory (sizeof (unsigned int));
|
|
||||||
if (servers_waiting == MAP_FAILED) {
|
|
||||||
log_message (LOG_ERR,
|
|
||||||
"Could not allocate memory for child counting.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
*servers_waiting = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create a "locking" file for use around the servers_waiting
|
|
||||||
* variable.
|
|
||||||
*/
|
|
||||||
_child_lock_init ();
|
|
||||||
|
|
||||||
if (child_config.startservers > child_config.maxclients) {
|
|
||||||
log_message (LOG_WARNING,
|
|
||||||
"Can not start more than \"MaxClients\" servers. "
|
|
||||||
"Starting %u servers instead.",
|
|
||||||
child_config.maxclients);
|
|
||||||
child_config.startservers = child_config.maxclients;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i != child_config.maxclients; i++) {
|
|
||||||
child_ptr[i].status = T_EMPTY;
|
|
||||||
child_ptr[i].connects = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i != child_config.startservers; i++) {
|
|
||||||
DEBUG2 ("Trying to create child %d of %d", i + 1,
|
|
||||||
child_config.startservers);
|
|
||||||
child_ptr[i].status = T_WAITING;
|
|
||||||
child_ptr[i].tid = child_make (&child_ptr[i]);
|
|
||||||
|
|
||||||
if (child_ptr[i].tid < 0) {
|
|
||||||
log_message (LOG_WARNING,
|
|
||||||
"Could not create child number %d of %d",
|
|
||||||
i, child_config.startservers);
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
log_message (LOG_INFO,
|
|
||||||
"Creating child number %d of %d ...",
|
|
||||||
i + 1, child_config.startservers);
|
|
||||||
|
|
||||||
SERVER_INC ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log_message (LOG_INFO, "Finished creating all children.");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Keep the proper number of servers running. This is the birth of the
|
|
||||||
* servers. It monitors this at least once a second.
|
|
||||||
*/
|
|
||||||
void child_main_loop (void)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
if (config.quit)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* If there are not enough spare servers, create more */
|
|
||||||
SERVER_COUNT_LOCK ();
|
|
||||||
if (*servers_waiting < child_config.minspareservers) {
|
|
||||||
log_message (LOG_NOTICE,
|
|
||||||
"Waiting servers (%d) is less than MinSpareServers (%d). "
|
|
||||||
"Creating new child.",
|
|
||||||
*servers_waiting,
|
|
||||||
child_config.minspareservers);
|
|
||||||
|
|
||||||
SERVER_COUNT_UNLOCK ();
|
|
||||||
|
|
||||||
for (i = 0; i != child_config.maxclients; i++) {
|
|
||||||
if (child_ptr[i].status == T_EMPTY) {
|
|
||||||
child_ptr[i].status = T_WAITING;
|
|
||||||
child_ptr[i].tid =
|
|
||||||
child_make (&child_ptr[i]);
|
|
||||||
if (child_ptr[i].tid < 0) {
|
|
||||||
log_message (LOG_NOTICE,
|
|
||||||
"Could not create child");
|
|
||||||
|
|
||||||
child_ptr[i].status = T_EMPTY;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
SERVER_INC ();
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SERVER_COUNT_UNLOCK ();
|
|
||||||
}
|
|
||||||
|
|
||||||
sleep (5);
|
|
||||||
|
|
||||||
/* Handle log rotation if it was requested */
|
/* Handle log rotation if it was requested */
|
||||||
if (received_sighup) {
|
if (received_sighup) {
|
||||||
@ -519,11 +124,117 @@ void child_main_loop (void)
|
|||||||
filter_reload ();
|
filter_reload ();
|
||||||
#endif /* FILTER_ENABLE */
|
#endif /* FILTER_ENABLE */
|
||||||
|
|
||||||
/* propagate filter reload to all children */
|
|
||||||
child_kill_children (SIGHUP);
|
|
||||||
|
|
||||||
received_sighup = FALSE;
|
received_sighup = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
|
||||||
|
for (i = 0; i < vector_length(listen_fds); i++) {
|
||||||
|
int *fd = (int *) vector_getentry(listen_fds, i, NULL);
|
||||||
|
|
||||||
|
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));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
FD_SET(*fd, &rfds);
|
||||||
|
maxfd = max(maxfd, *fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
continue;
|
||||||
|
} 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);
|
||||||
|
|
||||||
|
if (FD_ISSET(*fd, &rfds)) {
|
||||||
|
/*
|
||||||
|
* only accept the connection on the first
|
||||||
|
* fd that we find readable. - fair?
|
||||||
|
*/
|
||||||
|
listenfd = *fd;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listenfd == -1) {
|
||||||
|
log_message(LOG_WARNING, "Strange: None of our listen "
|
||||||
|
"fds was readable after select");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We have a socket that is readable.
|
||||||
|
* Continue handling this connection.
|
||||||
|
*/
|
||||||
|
|
||||||
|
connfd = accept (listenfd, cliaddr, &clilen);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure no error occurred...
|
||||||
|
*/
|
||||||
|
if (connfd < 0) {
|
||||||
|
log_message (LOG_ERR,
|
||||||
|
"Accept returned an error (%s) ... retrying.",
|
||||||
|
strerror (errno));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
child = safemalloc(sizeof(struct child));
|
||||||
|
if (!child) {
|
||||||
|
oom:
|
||||||
|
close(connfd);
|
||||||
|
log_message (LOG_CRIT,
|
||||||
|
"Could not allocate memory for child.");
|
||||||
|
usleep(16); /* prevent 100% CPU usage in OOM situation */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
child->done = 0;
|
||||||
|
|
||||||
|
if (!sblist_add(childs, &child)) {
|
||||||
|
free(child);
|
||||||
|
goto oom;
|
||||||
|
}
|
||||||
|
|
||||||
|
child->client.fd = connfd;
|
||||||
|
memcpy(&child->client.addr, &cliaddr_storage, sizeof(cliaddr_storage));
|
||||||
|
|
||||||
|
attrp = 0;
|
||||||
|
if (pthread_attr_init(&attr) == 0) {
|
||||||
|
attrp = &attr;
|
||||||
|
pthread_attr_setstacksize(attrp, 256*1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pthread_create(&child->thread, attrp, child_thread, child) != 0) {
|
||||||
|
sblist_delete(childs, sblist_getsize(childs) -1);
|
||||||
|
free(child);
|
||||||
|
goto oom;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -532,18 +243,32 @@ void child_main_loop (void)
|
|||||||
*/
|
*/
|
||||||
void child_kill_children (int sig)
|
void child_kill_children (int sig)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i != child_config.maxclients; i++) {
|
if (sig != SIGTERM) return;
|
||||||
if (child_ptr[i].status != T_EMPTY)
|
|
||||||
kill (child_ptr[i].tid, sig);
|
for (i = 0; i < sblist_getsize(childs); i++) {
|
||||||
}
|
struct child *c = *((struct child**)sblist_get(childs, i));
|
||||||
|
if (!c->done) {
|
||||||
|
/* interrupt blocking operations.
|
||||||
|
this should cause the threads to shutdown orderly. */
|
||||||
|
close(c->client.fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
usleep(16);
|
||||||
|
collect_threads();
|
||||||
|
if (sblist_getsize(childs) != 0)
|
||||||
|
log_message (LOG_CRIT,
|
||||||
|
"child_kill_children: %zu threads still alive!",
|
||||||
|
sblist_getsize(childs)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 +276,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,26 +284,28 @@ 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:
|
* 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;
|
||||||
}
|
}
|
||||||
@ -591,12 +318,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;
|
||||||
}
|
}
|
||||||
|
270
src/conf.c
270
src/conf.c
@ -27,7 +27,6 @@
|
|||||||
|
|
||||||
#include "acl.h"
|
#include "acl.h"
|
||||||
#include "anonymous.h"
|
#include "anonymous.h"
|
||||||
#include "child.h"
|
|
||||||
#include "filter.h"
|
#include "filter.h"
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
#include "html-error.h"
|
#include "html-error.h"
|
||||||
@ -93,7 +92,8 @@
|
|||||||
* All configuration handling functions are REQUIRED to be defined
|
* All configuration handling functions are REQUIRED to be defined
|
||||||
* with the same function template as below.
|
* with the same function template as below.
|
||||||
*/
|
*/
|
||||||
typedef int (*CONFFILE_HANDLER) (struct config_s *, const char *, regmatch_t[]);
|
typedef int (*CONFFILE_HANDLER) (struct config_s *, const char *,
|
||||||
|
unsigned long, regmatch_t[]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Define the pattern used by any directive handling function. The
|
* Define the pattern used by any directive handling function. The
|
||||||
@ -108,7 +108,7 @@ typedef int (*CONFFILE_HANDLER) (struct config_s *, const char *, regmatch_t[]);
|
|||||||
*/
|
*/
|
||||||
#define HANDLE_FUNC(func) \
|
#define HANDLE_FUNC(func) \
|
||||||
int func(struct config_s* conf, const char* line, \
|
int func(struct config_s* conf, const char* line, \
|
||||||
regmatch_t match[])
|
unsigned long lineno, regmatch_t match[])
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* List all the handling functions. These are defined later, but they need
|
* List all the handling functions. These are defined later, but they need
|
||||||
@ -141,9 +141,7 @@ static HANDLE_FUNC (handle_listen);
|
|||||||
static HANDLE_FUNC (handle_logfile);
|
static HANDLE_FUNC (handle_logfile);
|
||||||
static HANDLE_FUNC (handle_loglevel);
|
static HANDLE_FUNC (handle_loglevel);
|
||||||
static HANDLE_FUNC (handle_maxclients);
|
static HANDLE_FUNC (handle_maxclients);
|
||||||
static HANDLE_FUNC (handle_maxrequestsperchild);
|
static HANDLE_FUNC (handle_obsolete);
|
||||||
static HANDLE_FUNC (handle_maxspareservers);
|
|
||||||
static HANDLE_FUNC (handle_minspareservers);
|
|
||||||
static HANDLE_FUNC (handle_pidfile);
|
static HANDLE_FUNC (handle_pidfile);
|
||||||
static HANDLE_FUNC (handle_port);
|
static HANDLE_FUNC (handle_port);
|
||||||
#ifdef REVERSE_SUPPORT
|
#ifdef REVERSE_SUPPORT
|
||||||
@ -152,7 +150,6 @@ static HANDLE_FUNC (handle_reversemagic);
|
|||||||
static HANDLE_FUNC (handle_reverseonly);
|
static HANDLE_FUNC (handle_reverseonly);
|
||||||
static HANDLE_FUNC (handle_reversepath);
|
static HANDLE_FUNC (handle_reversepath);
|
||||||
#endif
|
#endif
|
||||||
static HANDLE_FUNC (handle_startservers);
|
|
||||||
static HANDLE_FUNC (handle_statfile);
|
static HANDLE_FUNC (handle_statfile);
|
||||||
static HANDLE_FUNC (handle_stathost);
|
static HANDLE_FUNC (handle_stathost);
|
||||||
static HANDLE_FUNC (handle_syslog);
|
static HANDLE_FUNC (handle_syslog);
|
||||||
@ -197,89 +194,95 @@ 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 */
|
},
|
||||||
STDCONF ("logfile", STR, handle_logfile),
|
/* string arguments */
|
||||||
STDCONF ("pidfile", STR, handle_pidfile),
|
STDCONF ("logfile", STR, handle_logfile),
|
||||||
STDCONF ("anonymous", STR, handle_anonymous),
|
STDCONF ("pidfile", STR, handle_pidfile),
|
||||||
STDCONF ("viaproxyname", STR, handle_viaproxyname),
|
STDCONF ("anonymous", STR, handle_anonymous),
|
||||||
STDCONF ("defaulterrorfile", STR, handle_defaulterrorfile),
|
STDCONF ("viaproxyname", STR, handle_viaproxyname),
|
||||||
STDCONF ("statfile", STR, handle_statfile),
|
STDCONF ("defaulterrorfile", STR, handle_defaulterrorfile),
|
||||||
STDCONF ("stathost", STR, handle_stathost),
|
STDCONF ("statfile", STR, handle_statfile),
|
||||||
STDCONF ("xtinyproxy", BOOL, handle_xtinyproxy),
|
STDCONF ("stathost", STR, handle_stathost),
|
||||||
/* boolean arguments */
|
STDCONF ("xtinyproxy", BOOL, handle_xtinyproxy),
|
||||||
STDCONF ("syslog", BOOL, handle_syslog),
|
/* boolean arguments */
|
||||||
STDCONF ("bindsame", BOOL, handle_bindsame),
|
STDCONF ("syslog", BOOL, handle_syslog),
|
||||||
STDCONF ("disableviaheader", BOOL, handle_disableviaheader),
|
STDCONF ("bindsame", BOOL, handle_bindsame),
|
||||||
/* integer arguments */
|
STDCONF ("disableviaheader", BOOL, handle_disableviaheader),
|
||||||
STDCONF ("port", INT, handle_port),
|
/* integer arguments */
|
||||||
STDCONF ("maxclients", INT, handle_maxclients),
|
STDCONF ("port", INT, handle_port),
|
||||||
STDCONF ("maxspareservers", INT, handle_maxspareservers),
|
STDCONF ("maxclients", INT, handle_maxclients),
|
||||||
STDCONF ("minspareservers", INT, handle_minspareservers),
|
STDCONF ("maxspareservers", INT, handle_obsolete),
|
||||||
STDCONF ("startservers", INT, handle_startservers),
|
STDCONF ("minspareservers", INT, handle_obsolete),
|
||||||
STDCONF ("maxrequestsperchild", INT, handle_maxrequestsperchild),
|
STDCONF ("startservers", INT, handle_obsolete),
|
||||||
STDCONF ("timeout", INT, handle_timeout),
|
STDCONF ("maxrequestsperchild", INT, handle_obsolete),
|
||||||
|
STDCONF ("timeout", INT, handle_timeout),
|
||||||
#ifdef UPSTREAM_SUPPORT
|
#ifdef UPSTREAM_SUPPORT
|
||||||
STDCONF ("deadtime", INT, handle_deadtime),
|
STDCONF ("deadtime", INT, handle_deadtime),
|
||||||
#endif
|
#endif
|
||||||
STDCONF ("connectport", INT, handle_connectport),
|
STDCONF ("connectport", INT, handle_connectport),
|
||||||
/* alphanumeric arguments */
|
/* alphanumeric arguments */
|
||||||
STDCONF ("user", ALNUM, handle_user),
|
STDCONF ("user", ALNUM, handle_user),
|
||||||
STDCONF ("group", ALNUM, handle_group),
|
STDCONF ("group", ALNUM, handle_group),
|
||||||
/* ip arguments */
|
/* ip arguments */
|
||||||
STDCONF ("listen", "(" IP "|" IPV6 ")", handle_listen),
|
STDCONF ("listen", "(" IP "|" IPV6 ")", handle_listen),
|
||||||
STDCONF ("allow", "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")",
|
STDCONF ("allow", "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")",
|
||||||
handle_allow),
|
handle_allow),
|
||||||
STDCONF ("deny", "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")",
|
STDCONF ("deny", "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")",
|
||||||
handle_deny),
|
handle_deny),
|
||||||
STDCONF ("bind", "(" IP "|" IPV6 ")", handle_bind),
|
STDCONF ("bind", "(" IP "|" IPV6 ")", handle_bind),
|
||||||
/* other */
|
/* other */
|
||||||
STDCONF ("basicauth", ALNUM WS ALNUM, handle_basicauth),
|
STDCONF ("basicauth", ALNUM WS ALNUM, handle_basicauth),
|
||||||
STDCONF ("errorfile", INT WS STR, handle_errorfile),
|
STDCONF ("errorfile", INT WS STR, handle_errorfile),
|
||||||
STDCONF ("addheader", STR WS STR, handle_addheader),
|
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 "(" "(" PIPE "(" IP
|
||||||
"(" IP "|" ALNUM ")" ":" INT "(" "(" PIPE "(" IP
|
"|" ALNUM ")" ":" INT ")+" ")?" "(" WS STR ")?"
|
||||||
"|" ALNUM ")" ":" INT ")+" ")?" "(" WS STR ")?"
|
END, handle_upstream, NULL
|
||||||
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 free_added_headers (vector_t add_headers)
|
static void
|
||||||
|
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);
|
||||||
@ -295,18 +298,18 @@ void free_config (struct config_s *conf)
|
|||||||
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 +321,7 @@ 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,7 +330,8 @@ void free_config (struct config_s *conf)
|
|||||||
*
|
*
|
||||||
* Returns 0 on success; negative upon failure.
|
* Returns 0 on success; negative upon failure.
|
||||||
*/
|
*/
|
||||||
int config_compile_regex (void)
|
int
|
||||||
|
config_compile_regex (void)
|
||||||
{
|
{
|
||||||
unsigned int i, r;
|
unsigned int i, r;
|
||||||
|
|
||||||
@ -355,7 +359,8 @@ int 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 config_free_regex (void)
|
static void
|
||||||
|
config_free_regex (void)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
@ -376,7 +381,8 @@ static void config_free_regex (void)
|
|||||||
* Returns 0 if a match was found and successfully processed; otherwise,
|
* Returns 0 if a match was found and successfully processed; otherwise,
|
||||||
* a negative number is returned.
|
* a negative number is returned.
|
||||||
*/
|
*/
|
||||||
static int check_match (struct config_s *conf, const char *line)
|
static int check_match (struct config_s *conf, const char *line,
|
||||||
|
unsigned long lineno)
|
||||||
{
|
{
|
||||||
regmatch_t match[RE_MAX_MATCHES];
|
regmatch_t match[RE_MAX_MATCHES];
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
@ -386,7 +392,7 @@ static int check_match (struct config_s *conf, const char *line)
|
|||||||
assert (directives[i].cre);
|
assert (directives[i].cre);
|
||||||
if (!regexec
|
if (!regexec
|
||||||
(directives[i].cre, line, RE_MAX_MATCHES, match, 0))
|
(directives[i].cre, line, RE_MAX_MATCHES, match, 0))
|
||||||
return (*directives[i].handler) (conf, line, match);
|
return (*directives[i].handler) (conf, line, lineno, match);
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
@ -401,7 +407,7 @@ static int config_parse (struct config_s *conf, FILE * f)
|
|||||||
unsigned long lineno = 1;
|
unsigned long lineno = 1;
|
||||||
|
|
||||||
while (fgets (buffer, sizeof (buffer), f)) {
|
while (fgets (buffer, sizeof (buffer), f)) {
|
||||||
if (check_match (conf, buffer)) {
|
if (check_match (conf, buffer, lineno)) {
|
||||||
printf ("Syntax error on line %ld\n", lineno);
|
printf ("Syntax error on line %ld\n", lineno);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -473,16 +479,17 @@ 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);
|
||||||
@ -491,7 +498,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;
|
||||||
@ -508,8 +515,9 @@ static void initialize_with_defaults (struct config_s *conf,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef UPSTREAM_SUPPORT
|
#ifdef UPSTREAM_SUPPORT
|
||||||
|
conf->upstream_list = NULL;
|
||||||
/* 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);
|
||||||
@ -668,7 +676,8 @@ set_bool_arg (unsigned int *var, const char *line, regmatch_t * match)
|
|||||||
return 0;
|
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 (line);
|
||||||
assert (match && match->rm_so != -1);
|
assert (match && match->rm_so != -1);
|
||||||
@ -676,7 +685,8 @@ static unsigned long 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 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 (var);
|
||||||
assert (line);
|
assert (line);
|
||||||
@ -733,7 +743,8 @@ 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'", conf->via_proxy_name);
|
"Setting \"Via\" header to '%s'",
|
||||||
|
conf->via_proxy_name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -745,7 +756,8 @@ static HANDLE_FUNC (handle_disableviaheader)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_message (LOG_INFO, "Disabling transmission of the \"Via\" header.");
|
log_message (LOG_INFO,
|
||||||
|
"Disabling transmission of the \"Via\" header.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -810,32 +822,14 @@ static HANDLE_FUNC (handle_port)
|
|||||||
|
|
||||||
static HANDLE_FUNC (handle_maxclients)
|
static HANDLE_FUNC (handle_maxclients)
|
||||||
{
|
{
|
||||||
child_configure (CHILD_MAXCLIENTS, get_long_arg (line, &match[2]));
|
set_int_arg (&conf->maxclients, line, &match[2]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HANDLE_FUNC (handle_maxspareservers)
|
static HANDLE_FUNC (handle_obsolete)
|
||||||
{
|
{
|
||||||
child_configure (CHILD_MAXSPARESERVERS, get_long_arg (line, &match[2]));
|
fprintf (stderr, "WARNING: obsolete config item on line %lu\n",
|
||||||
return 0;
|
lineno);
|
||||||
}
|
|
||||||
|
|
||||||
static HANDLE_FUNC (handle_minspareservers)
|
|
||||||
{
|
|
||||||
child_configure (CHILD_MINSPARESERVERS, get_long_arg (line, &match[2]));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static HANDLE_FUNC (handle_startservers)
|
|
||||||
{
|
|
||||||
child_configure (CHILD_STARTSERVERS, get_long_arg (line, &match[2]));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static HANDLE_FUNC (handle_maxrequestsperchild)
|
|
||||||
{
|
|
||||||
child_configure (CHILD_MAXREQUESTSPERCHILD,
|
|
||||||
get_long_arg (line, &match[2]));
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -906,18 +900,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;
|
||||||
@ -1004,10 +998,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;
|
||||||
@ -1099,19 +1093,19 @@ 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)
|
||||||
@ -1124,8 +1118,8 @@ static HANDLE_FUNC (handle_upstream)
|
|||||||
pltr = plist = (upstream_proxy_list_t *)
|
pltr = plist = (upstream_proxy_list_t *)
|
||||||
safemalloc (sizeof (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)
|
||||||
|
@ -45,6 +45,7 @@ struct config_s {
|
|||||||
char *stathost;
|
char *stathost;
|
||||||
unsigned int godaemon; /* boolean */
|
unsigned int godaemon; /* boolean */
|
||||||
unsigned int quit; /* boolean */
|
unsigned int quit; /* boolean */
|
||||||
|
unsigned int maxclients;
|
||||||
char *user;
|
char *user;
|
||||||
char *group;
|
char *group;
|
||||||
vector_t listen_addrs;
|
vector_t listen_addrs;
|
||||||
|
@ -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;
|
||||||
|
@ -31,7 +31,6 @@
|
|||||||
#include "stats.h"
|
#include "stats.h"
|
||||||
|
|
||||||
struct conn_s *initialize_conn (int client_fd, const char *ipaddr,
|
struct conn_s *initialize_conn (int client_fd, const char *ipaddr,
|
||||||
const char *string_addr,
|
|
||||||
const char *sock_ipaddr)
|
const char *sock_ipaddr)
|
||||||
{
|
{
|
||||||
struct conn_s *connptr;
|
struct conn_s *connptr;
|
||||||
@ -79,7 +78,6 @@ struct conn_s *initialize_conn (int client_fd, const char *ipaddr,
|
|||||||
connptr->server_ip_addr = (sock_ipaddr ?
|
connptr->server_ip_addr = (sock_ipaddr ?
|
||||||
safestrdup (sock_ipaddr) : NULL);
|
safestrdup (sock_ipaddr) : NULL);
|
||||||
connptr->client_ip_addr = safestrdup (ipaddr);
|
connptr->client_ip_addr = safestrdup (ipaddr);
|
||||||
connptr->client_string_addr = safestrdup (string_addr);
|
|
||||||
|
|
||||||
connptr->upstream_proxy = NULL;
|
connptr->upstream_proxy = NULL;
|
||||||
|
|
||||||
@ -134,8 +132,6 @@ void destroy_conn (struct conn_s *connptr)
|
|||||||
safefree (connptr->server_ip_addr);
|
safefree (connptr->server_ip_addr);
|
||||||
if (connptr->client_ip_addr)
|
if (connptr->client_ip_addr)
|
||||||
safefree (connptr->client_ip_addr);
|
safefree (connptr->client_ip_addr);
|
||||||
if (connptr->client_string_addr)
|
|
||||||
safefree (connptr->client_string_addr);
|
|
||||||
|
|
||||||
#ifdef REVERSE_SUPPORT
|
#ifdef REVERSE_SUPPORT
|
||||||
if (connptr->reversepath)
|
if (connptr->reversepath)
|
||||||
|
@ -62,10 +62,9 @@ struct conn_s {
|
|||||||
char *server_ip_addr;
|
char *server_ip_addr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Store the client's IP and hostname information
|
* Store the client's IP information
|
||||||
*/
|
*/
|
||||||
char *client_ip_addr;
|
char *client_ip_addr;
|
||||||
char *client_string_addr;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Store the incoming request's HTTP protocol.
|
* Store the incoming request's HTTP protocol.
|
||||||
@ -92,7 +91,6 @@ struct conn_s {
|
|||||||
* Functions for the creation and destruction of a connection structure.
|
* Functions for the creation and destruction of a connection structure.
|
||||||
*/
|
*/
|
||||||
extern struct conn_s *initialize_conn (int client_fd, const char *ipaddr,
|
extern struct conn_s *initialize_conn (int client_fd, const char *ipaddr,
|
||||||
const char *string_addr,
|
|
||||||
const char *sock_ipaddr);
|
const char *sock_ipaddr);
|
||||||
extern void destroy_conn (struct conn_s *connptr);
|
extern void destroy_conn (struct conn_s *connptr);
|
||||||
|
|
||||||
|
@ -41,9 +41,10 @@ void makedaemon (void)
|
|||||||
if (fork () != 0)
|
if (fork () != 0)
|
||||||
exit (0);
|
exit (0);
|
||||||
|
|
||||||
if (chdir ("/") != 0) {
|
if (chdir ("/") != 0) {
|
||||||
log_message (LOG_WARNING, "Could not change directory to /");
|
log_message (LOG_WARNING,
|
||||||
}
|
"Could not change directory to /");
|
||||||
|
}
|
||||||
|
|
||||||
umask (0177);
|
umask (0177);
|
||||||
|
|
||||||
|
10
src/filter.c
10
src/filter.c
@ -104,11 +104,13 @@ void filter_init (void)
|
|||||||
if (*s == '\0')
|
if (*s == '\0')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!p) /* head of list */
|
if (!p) /* head of list */
|
||||||
fl = p = (struct filter_list *)
|
fl = p =
|
||||||
|
(struct filter_list *)
|
||||||
safecalloc (1, sizeof (struct filter_list));
|
safecalloc (1, sizeof (struct filter_list));
|
||||||
else { /* next entry */
|
else { /* next entry */
|
||||||
p->next = (struct filter_list *)
|
p->next =
|
||||||
|
(struct filter_list *)
|
||||||
safecalloc (1, sizeof (struct filter_list));
|
safecalloc (1, sizeof (struct filter_list));
|
||||||
p = p->next;
|
p = p->next;
|
||||||
}
|
}
|
||||||
|
@ -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,7 +508,8 @@ 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, &key, (void **) &data) < 0)
|
if (hashmap_return_entry (map, result_iter,
|
||||||
|
&key, (void **) &data) < 0)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
return (data);
|
return (data);
|
||||||
|
58
src/heap.c
58
src/heap.c
@ -97,61 +97,3 @@ char *debugging_strdup (const char *s, const char *file, unsigned long line)
|
|||||||
|
|
||||||
#endif /* !NDEBUG */
|
#endif /* !NDEBUG */
|
||||||
|
|
||||||
/*
|
|
||||||
* Allocate a block of memory in the "shared" memory region.
|
|
||||||
*
|
|
||||||
* FIXME: This uses the most basic (and slowest) means of creating a
|
|
||||||
* shared memory location. It requires the use of a temporary file. We might
|
|
||||||
* want to look into something like MM (Shared Memory Library) for a better
|
|
||||||
* solution.
|
|
||||||
*/
|
|
||||||
void *malloc_shared_memory (size_t size)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
void *ptr;
|
|
||||||
char buffer[32];
|
|
||||||
|
|
||||||
static const char *shared_file = "/tmp/tinyproxy.shared.XXXXXX";
|
|
||||||
|
|
||||||
assert (size > 0);
|
|
||||||
|
|
||||||
strlcpy (buffer, shared_file, sizeof (buffer));
|
|
||||||
|
|
||||||
/* Only allow u+rw bits. This may be required for some versions
|
|
||||||
* of glibc so that mkstemp() doesn't make us vulnerable.
|
|
||||||
*/
|
|
||||||
umask (0177);
|
|
||||||
|
|
||||||
if ((fd = mkstemp (buffer)) == -1)
|
|
||||||
return MAP_FAILED;
|
|
||||||
unlink (buffer);
|
|
||||||
|
|
||||||
if (ftruncate (fd, size) == -1)
|
|
||||||
return MAP_FAILED;
|
|
||||||
ptr = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Allocate a block of memory from the "shared" region an initialize it to
|
|
||||||
* zero.
|
|
||||||
*/
|
|
||||||
void *calloc_shared_memory (size_t nmemb, size_t size)
|
|
||||||
{
|
|
||||||
void *ptr;
|
|
||||||
long length;
|
|
||||||
|
|
||||||
assert (nmemb > 0);
|
|
||||||
assert (size > 0);
|
|
||||||
|
|
||||||
length = nmemb * size;
|
|
||||||
|
|
||||||
ptr = malloc_shared_memory (length);
|
|
||||||
if (ptr == MAP_FAILED)
|
|
||||||
return ptr;
|
|
||||||
|
|
||||||
memset (ptr, 0, length);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
@ -52,10 +52,4 @@ extern char *debugging_strdup (const char *s, const char *file,
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* Allocate memory from the "shared" region of memory.
|
|
||||||
*/
|
|
||||||
extern void *malloc_shared_memory (size_t size);
|
|
||||||
extern void *calloc_shared_memory (size_t nmemb, size_t size);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -86,7 +86,8 @@ 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 send_html_file (FILE * infile, struct conn_s *connptr)
|
int
|
||||||
|
send_html_file (FILE *infile, struct conn_s *connptr)
|
||||||
{
|
{
|
||||||
char *inbuf;
|
char *inbuf;
|
||||||
char *varstart = NULL;
|
char *varstart = NULL;
|
||||||
@ -104,9 +105,8 @@ int 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
|
lookup_variable (connptr->error_variables,
|
||||||
(connptr->error_variables,
|
varstart);
|
||||||
varstart);
|
|
||||||
if (!varval)
|
if (!varval)
|
||||||
varval = "(unknown)";
|
varval = "(unknown)";
|
||||||
r = write_message (connptr->client_fd,
|
r = write_message (connptr->client_fd,
|
||||||
@ -160,21 +160,25 @@ 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" "%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[] =
|
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[] =
|
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
|
/* according to rfc7235, the 407 error must be accompanied by
|
||||||
* a Proxy-Authenticate header field. */
|
a Proxy-Authenticate header field. */
|
||||||
const char *add =
|
const char *add = code == 407 ? p_auth_str : (code == 401 ? w_auth_str : "");
|
||||||
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, add));
|
code, message, PACKAGE, VERSION,
|
||||||
|
add));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -203,12 +207,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 =
|
char *detail = lookup_variable (connptr->error_variables, "detail");
|
||||||
lookup_variable (connptr->error_variables, "detail");
|
return (write_message (connptr->client_fd, fallback_error,
|
||||||
return (write_message
|
connptr->error_number,
|
||||||
(connptr->client_fd, fallback_error,
|
connptr->error_string,
|
||||||
connptr->error_number, connptr->error_string,
|
connptr->error_string,
|
||||||
connptr->error_string, detail, PACKAGE, VERSION));
|
detail, PACKAGE, VERSION));
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = send_html_file (infile, connptr);
|
ret = send_html_file (infile, connptr);
|
||||||
@ -258,7 +262,6 @@ int add_standard_vars (struct conn_s *connptr)
|
|||||||
ADD_VAR_RET ("cause", connptr->error_string);
|
ADD_VAR_RET ("cause", connptr->error_string);
|
||||||
ADD_VAR_RET ("request", connptr->request_line);
|
ADD_VAR_RET ("request", connptr->request_line);
|
||||||
ADD_VAR_RET ("clientip", connptr->client_ip_addr);
|
ADD_VAR_RET ("clientip", connptr->client_ip_addr);
|
||||||
ADD_VAR_RET ("clienthost", connptr->client_string_addr);
|
|
||||||
|
|
||||||
/* The following value parts are all non-NULL and will
|
/* The following value parts are all non-NULL and will
|
||||||
* trigger warnings in ADD_VAR_RET(), so we use
|
* trigger warnings in ADD_VAR_RET(), so we use
|
||||||
@ -270,7 +273,8 @@ 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", "https://tinyproxy.github.io/");
|
add_error_variable (connptr, "website",
|
||||||
|
"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);
|
||||||
|
|
||||||
|
43
src/log.c
43
src/log.c
@ -29,6 +29,7 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
static const char *syslog_level[] = {
|
static const char *syslog_level[] = {
|
||||||
NULL,
|
NULL,
|
||||||
@ -45,6 +46,8 @@ static const char *syslog_level[] = {
|
|||||||
#define TIME_LENGTH 16
|
#define TIME_LENGTH 16
|
||||||
#define STRING_LENGTH 800
|
#define STRING_LENGTH 800
|
||||||
|
|
||||||
|
static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Global file descriptor for the log file
|
* Global file descriptor for the log file
|
||||||
*/
|
*/
|
||||||
@ -63,7 +66,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 +74,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 +89,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,16 +164,18 @@ 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) {
|
||||||
|
pthread_mutex_lock(&log_mutex);
|
||||||
#ifdef HAVE_VSYSLOG_H
|
#ifdef HAVE_VSYSLOG_H
|
||||||
vsyslog (level, fmt, args);
|
vsyslog (level, fmt, args);
|
||||||
#else
|
#else
|
||||||
vsnprintf (str, STRING_LENGTH, fmt, args);
|
vsnprintf (str, STRING_LENGTH, fmt, args);
|
||||||
syslog (level, "%s", str);
|
syslog (level, "%s", str);
|
||||||
#endif
|
#endif
|
||||||
|
pthread_mutex_unlock(&log_mutex);
|
||||||
} else {
|
} else {
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
@ -187,27 +192,33 @@ 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);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&log_mutex);
|
||||||
ret = write (log_file_fd, str, strlen (str));
|
ret = write (log_file_fd, str, strlen (str));
|
||||||
|
pthread_mutex_unlock(&log_mutex);
|
||||||
|
|
||||||
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&log_mutex);
|
||||||
fsync (log_file_fd);
|
fsync (log_file_fd);
|
||||||
|
pthread_mutex_unlock(&log_mutex);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@ -227,7 +238,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 +263,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");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
76
src/loop.c
Normal file
76
src/loop.c
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#include <pthread.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "loop.h"
|
||||||
|
#include "conf.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "sblist.h"
|
||||||
|
#include "sock.h"
|
||||||
|
|
||||||
|
struct loop_record {
|
||||||
|
union sockaddr_union addr;
|
||||||
|
time_t tstamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
static sblist *loop_records;
|
||||||
|
static pthread_mutex_t loop_records_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
void loop_records_init(void) {
|
||||||
|
loop_records = sblist_new(sizeof (struct loop_record), 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void su_to_str(union sockaddr_union *addr, char *buf) {
|
||||||
|
int af = addr->v4.sin_family;
|
||||||
|
unsigned port = ntohs(af == AF_INET ? addr->v4.sin_port : addr->v6.sin6_port);
|
||||||
|
char portb[32];
|
||||||
|
sprintf(portb, ":%u", port);
|
||||||
|
getpeer_information (addr, buf, 256);
|
||||||
|
strcat(buf, portb);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void loop_records_add(union sockaddr_union *addr) {
|
||||||
|
time_t now =time(0);
|
||||||
|
struct loop_record rec;
|
||||||
|
pthread_mutex_lock(&loop_records_lock);
|
||||||
|
rec.tstamp = now;
|
||||||
|
rec.addr = *addr;
|
||||||
|
sblist_add(loop_records, &rec);
|
||||||
|
pthread_mutex_unlock(&loop_records_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TIMEOUT_SECS 15
|
||||||
|
|
||||||
|
int connection_loops (union sockaddr_union *addr) {
|
||||||
|
int ret = 0, af, our_af = addr->v4.sin_family;
|
||||||
|
void *ipdata, *our_ipdata = our_af == AF_INET ? (void*)&addr->v4.sin_addr.s_addr : (void*)&addr->v6.sin6_addr.s6_addr;
|
||||||
|
size_t i, cmp_len = our_af == AF_INET ? sizeof(addr->v4.sin_addr.s_addr) : sizeof(addr->v6.sin6_addr.s6_addr);
|
||||||
|
unsigned port, our_port = ntohs(our_af == AF_INET ? addr->v4.sin_port : addr->v6.sin6_port);
|
||||||
|
time_t now = time(0);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&loop_records_lock);
|
||||||
|
for (i = 0; i < sblist_getsize(loop_records); ) {
|
||||||
|
struct loop_record *rec = sblist_get(loop_records, i);
|
||||||
|
|
||||||
|
if (rec->tstamp + TIMEOUT_SECS < now) {
|
||||||
|
sblist_delete(loop_records, i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
|
af = rec->addr.v4.sin_family;
|
||||||
|
if (af != our_af) goto next;
|
||||||
|
port = ntohs(af == AF_INET ? rec->addr.v4.sin_port : rec->addr.v6.sin6_port);
|
||||||
|
if (port != our_port) goto next;
|
||||||
|
ipdata = af == AF_INET ? (void*)&rec->addr.v4.sin_addr.s_addr : (void*)&rec->addr.v6.sin6_addr.s6_addr;
|
||||||
|
if (!memcmp(ipdata, our_ipdata, cmp_len)) {
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next:
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&loop_records_lock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
11
src/loop.h
Normal file
11
src/loop.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef LOOP_H
|
||||||
|
#define LOOP_H
|
||||||
|
|
||||||
|
#include "sock.h"
|
||||||
|
|
||||||
|
void loop_records_init(void);
|
||||||
|
void loop_records_add(union sockaddr_union *addr);
|
||||||
|
int connection_loops (union sockaddr_union *addr);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
48
src/main.c
48
src/main.c
@ -54,7 +54,8 @@ unsigned int received_sighup = FALSE; /* boolean */
|
|||||||
/*
|
/*
|
||||||
* Handle a signal
|
* Handle a signal
|
||||||
*/
|
*/
|
||||||
static void takesig (int sig)
|
static void
|
||||||
|
takesig (int sig)
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int status;
|
int status;
|
||||||
@ -64,6 +65,7 @@ static void takesig (int sig)
|
|||||||
received_sighup = TRUE;
|
received_sighup = TRUE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SIGINT:
|
||||||
case SIGTERM:
|
case SIGTERM:
|
||||||
config.quit = TRUE;
|
config.quit = TRUE;
|
||||||
break;
|
break;
|
||||||
@ -79,7 +81,8 @@ static void takesig (int sig)
|
|||||||
/*
|
/*
|
||||||
* Display the version information for the user.
|
* Display the version information for the user.
|
||||||
*/
|
*/
|
||||||
static void display_version (void)
|
static void
|
||||||
|
display_version (void)
|
||||||
{
|
{
|
||||||
printf ("%s %s\n", PACKAGE, VERSION);
|
printf ("%s %s\n", PACKAGE, VERSION);
|
||||||
}
|
}
|
||||||
@ -87,7 +90,8 @@ static void display_version (void)
|
|||||||
/*
|
/*
|
||||||
* Display usage to the user.
|
* Display usage to the user.
|
||||||
*/
|
*/
|
||||||
static void display_usage (void)
|
static void
|
||||||
|
display_usage (void)
|
||||||
{
|
{
|
||||||
int features = 0;
|
int features = 0;
|
||||||
|
|
||||||
@ -140,7 +144,8 @@ static void display_usage (void)
|
|||||||
"<https://tinyproxy.github.io/>.\n");
|
"<https://tinyproxy.github.io/>.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_id (char *str)
|
static int
|
||||||
|
get_id (char *str)
|
||||||
{
|
{
|
||||||
char *tstr;
|
char *tstr;
|
||||||
|
|
||||||
@ -164,7 +169,8 @@ static int get_id (char *str)
|
|||||||
*
|
*
|
||||||
* This function parses command line arguments.
|
* 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;
|
int opt;
|
||||||
|
|
||||||
@ -210,7 +216,8 @@ static void 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 change_user (const char *program)
|
static void
|
||||||
|
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);
|
||||||
@ -234,6 +241,7 @@ static void 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) {
|
||||||
@ -278,7 +286,7 @@ static void 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) {
|
||||||
@ -298,6 +306,7 @@ static void initialize_config_defaults (struct config_s *conf)
|
|||||||
#endif
|
#endif
|
||||||
conf->logf_name = NULL;
|
conf->logf_name = NULL;
|
||||||
conf->pidpath = NULL;
|
conf->pidpath = NULL;
|
||||||
|
conf->maxclients = 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -322,8 +331,11 @@ done:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main (int argc, char **argv)
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
srand(time(NULL)); /* for hashmap seeds */
|
||||||
|
|
||||||
/* 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.
|
||||||
*/
|
*/
|
||||||
@ -331,7 +343,7 @@ int 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,7 +351,8 @@ int 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_defaults)) {
|
&config,
|
||||||
|
&config_defaults)) {
|
||||||
exit (EX_SOFTWARE);
|
exit (EX_SOFTWARE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,8 +369,8 @@ int 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 ();
|
||||||
}
|
}
|
||||||
@ -367,13 +380,14 @@ int 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);
|
||||||
@ -400,13 +414,6 @@ int main (int argc, char **argv)
|
|||||||
exit (EX_SOFTWARE);
|
exit (EX_SOFTWARE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child_pool_create () < 0) {
|
|
||||||
fprintf (stderr,
|
|
||||||
"%s: Could not create the pool of children.\n",
|
|
||||||
argv[0]);
|
|
||||||
exit (EX_SOFTWARE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* These signals are only for the parent process. */
|
/* These signals are only for the parent process. */
|
||||||
log_message (LOG_INFO, "Setting the various signals.");
|
log_message (LOG_INFO, "Setting the various signals.");
|
||||||
|
|
||||||
@ -444,6 +451,7 @@ int 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 ();
|
||||||
|
@ -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,7 +204,8 @@ ssize_t readline (int fd, char **whole_buffer)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
line_ptr->next = (struct read_lines_s *)
|
line_ptr->next =
|
||||||
|
(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;
|
||||||
|
196
src/reqs.c
196
src/reqs.c
@ -49,6 +49,7 @@
|
|||||||
#include "connect-ports.h"
|
#include "connect-ports.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "basicauth.h"
|
#include "basicauth.h"
|
||||||
|
#include "loop.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Maximum length of a HTTP line
|
* Maximum length of a HTTP line
|
||||||
@ -60,13 +61,13 @@
|
|||||||
* enabled.
|
* enabled.
|
||||||
*/
|
*/
|
||||||
#ifdef UPSTREAM_SUPPORT
|
#ifdef UPSTREAM_SUPPORT
|
||||||
#define UPSTREAM_CONFIGURED() (config.upstream_list != NULL)
|
# define UPSTREAM_CONFIGURED() (config.upstream_list != NULL)
|
||||||
#define UPSTREAM_REQUEST(request) upstream_get(request, config.upstream_list)
|
# define UPSTREAM_REQUEST(request) upstream_get(request, config.upstream_list)
|
||||||
#define UPSTREAM_IS_HTTP(conn) (conn->upstream_proxy != NULL && conn->upstream_proxy->type == PT_HTTP)
|
# define UPSTREAM_IS_HTTP(conn) (conn->upstream_proxy != NULL && conn->upstream_proxy->type == PT_HTTP)
|
||||||
#else
|
#else
|
||||||
#define UPSTREAM_CONFIGURED() (0)
|
# define UPSTREAM_CONFIGURED() (0)
|
||||||
#define UPSTREAM_REQUEST(request) (request->host)
|
# define UPSTREAM_REQUEST(request) (request->host)
|
||||||
#define UPSTREAM_IS_HTTP(up) (0)
|
# define UPSTREAM_IS_HTTP(up) (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -231,8 +232,8 @@ static int extract_url (const char *lurl, const char *surl, int default_port,
|
|||||||
/* Remove any surrounding '[' and ']' from IPv6 literals */
|
/* Remove any surrounding '[' and ']' from IPv6 literals */
|
||||||
p = strrchr (request->host, ']');
|
p = strrchr (request->host, ']');
|
||||||
if (p && (*(request->host) == '[')) {
|
if (p && (*(request->host) == '[')) {
|
||||||
memmove (request->host, request->host + 1,
|
memmove(request->host, request->host + 1,
|
||||||
strlen (request->host) - 2);
|
strlen(request->host) - 2);
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
p--;
|
p--;
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
@ -257,7 +258,7 @@ static int
|
|||||||
establish_http_connection (struct conn_s *connptr, struct request_s *request)
|
establish_http_connection (struct conn_s *connptr, struct request_s *request)
|
||||||
{
|
{
|
||||||
char portbuff[7];
|
char portbuff[7];
|
||||||
char dst[sizeof (struct in6_addr)];
|
char dst[sizeof(struct in6_addr)];
|
||||||
|
|
||||||
/* Build a port string if it's not a standard port */
|
/* Build a port string if it's not a standard port */
|
||||||
if (request->port != HTTP_PORT && request->port != HTTP_PORT_SSL)
|
if (request->port != HTTP_PORT && request->port != HTTP_PORT_SSL)
|
||||||
@ -265,7 +266,7 @@ establish_http_connection (struct conn_s *connptr, struct request_s *request)
|
|||||||
else
|
else
|
||||||
portbuff[0] = '\0';
|
portbuff[0] = '\0';
|
||||||
|
|
||||||
if (inet_pton (AF_INET6, request->host, dst) > 0) {
|
if (inet_pton(AF_INET6, request->host, dst) > 0) {
|
||||||
/* host is an IPv6 address literal, so surround it with
|
/* host is an IPv6 address literal, so surround it with
|
||||||
* [] */
|
* [] */
|
||||||
return write_message (connptr->server_fd,
|
return write_message (connptr->server_fd,
|
||||||
@ -423,7 +424,8 @@ BAD_REQUEST_ERROR:
|
|||||||
|
|
||||||
/* Verify that the port in the CONNECT method is allowed */
|
/* Verify that the port in the CONNECT method is allowed */
|
||||||
if (!check_allowed_connect_ports (request->port,
|
if (!check_allowed_connect_ports (request->port,
|
||||||
config.connect_ports)) {
|
config.connect_ports))
|
||||||
|
{
|
||||||
indicate_http_error (connptr, 403, "Access violation",
|
indicate_http_error (connptr, 403, "Access violation",
|
||||||
"detail",
|
"detail",
|
||||||
"The CONNECT method not allowed "
|
"The CONNECT method not allowed "
|
||||||
@ -541,8 +543,8 @@ static int pull_client_data (struct conn_s *connptr, long int length)
|
|||||||
*/
|
*/
|
||||||
ret = socket_nonblocking (connptr->client_fd);
|
ret = socket_nonblocking (connptr->client_fd);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
log_message (LOG_ERR, "Failed to set the client socket "
|
log_message(LOG_ERR, "Failed to set the client socket "
|
||||||
"to non-blocking: %s", strerror (errno));
|
"to non-blocking: %s", strerror (errno));
|
||||||
goto ERROR_EXIT;
|
goto ERROR_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -550,8 +552,8 @@ static int pull_client_data (struct conn_s *connptr, long int length)
|
|||||||
|
|
||||||
ret = socket_blocking (connptr->client_fd);
|
ret = socket_blocking (connptr->client_fd);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
log_message (LOG_ERR, "Failed to set the client socket "
|
log_message(LOG_ERR, "Failed to set the client socket "
|
||||||
"to blocking: %s", strerror (errno));
|
"to blocking: %s", strerror (errno));
|
||||||
goto ERROR_EXIT;
|
goto ERROR_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -564,8 +566,8 @@ static int pull_client_data (struct conn_s *connptr, long int length)
|
|||||||
bytes_read = read (connptr->client_fd, buffer, 2);
|
bytes_read = read (connptr->client_fd, buffer, 2);
|
||||||
if (bytes_read == -1) {
|
if (bytes_read == -1) {
|
||||||
log_message
|
log_message
|
||||||
(LOG_WARNING,
|
(LOG_WARNING,
|
||||||
"Could not read two bytes from POST message");
|
"Could not read two bytes from POST message");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -872,7 +874,7 @@ process_client_headers (struct conn_s *connptr, hashmap_t hashofheaders)
|
|||||||
* http proxy is in use.)
|
* http proxy is in use.)
|
||||||
*/
|
*/
|
||||||
if (connptr->server_fd == -1 || connptr->show_stats
|
if (connptr->server_fd == -1 || connptr->show_stats
|
||||||
|| (connptr->connect_method && !UPSTREAM_IS_HTTP (connptr))) {
|
|| (connptr->connect_method && ! UPSTREAM_IS_HTTP (connptr))) {
|
||||||
log_message (LOG_INFO,
|
log_message (LOG_INFO,
|
||||||
"Not sending client headers to remote machine");
|
"Not sending client headers to remote machine");
|
||||||
return 0;
|
return 0;
|
||||||
@ -1091,8 +1093,8 @@ retry:
|
|||||||
while (reverse) {
|
while (reverse) {
|
||||||
if (strncasecmp (header,
|
if (strncasecmp (header,
|
||||||
reverse->url, (len =
|
reverse->url, (len =
|
||||||
strlen (reverse->url)))
|
strlen (reverse->
|
||||||
== 0)
|
url))) == 0)
|
||||||
break;
|
break;
|
||||||
reverse = reverse->next;
|
reverse = reverse->next;
|
||||||
}
|
}
|
||||||
@ -1163,15 +1165,15 @@ static void relay_connection (struct conn_s *connptr)
|
|||||||
|
|
||||||
ret = socket_nonblocking (connptr->client_fd);
|
ret = socket_nonblocking (connptr->client_fd);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
log_message (LOG_ERR, "Failed to set the client socket "
|
log_message(LOG_ERR, "Failed to set the client socket "
|
||||||
"to non-blocking: %s", strerror (errno));
|
"to non-blocking: %s", strerror (errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = socket_nonblocking (connptr->server_fd);
|
ret = socket_nonblocking (connptr->server_fd);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
log_message (LOG_ERR, "Failed to set the server socket "
|
log_message(LOG_ERR, "Failed to set the server socket "
|
||||||
"to non-blocking: %s", strerror (errno));
|
"to non-blocking: %s", strerror (errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1250,9 +1252,9 @@ static void relay_connection (struct conn_s *connptr)
|
|||||||
*/
|
*/
|
||||||
ret = socket_blocking (connptr->client_fd);
|
ret = socket_blocking (connptr->client_fd);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
log_message (LOG_ERR,
|
log_message(LOG_ERR,
|
||||||
"Failed to set client socket to blocking: %s",
|
"Failed to set client socket to blocking: %s",
|
||||||
strerror (errno));
|
strerror (errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1282,41 +1284,41 @@ static void relay_connection (struct conn_s *connptr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
connect_to_upstream_proxy (struct conn_s *connptr, struct request_s *request)
|
connect_to_upstream_proxy(struct conn_s *connptr, struct request_s *request)
|
||||||
{
|
{
|
||||||
unsigned len;
|
unsigned len;
|
||||||
unsigned char buff[512]; /* won't use more than 7 + 255 */
|
unsigned char buff[512]; /* won't use more than 7 + 255 */
|
||||||
unsigned short port;
|
unsigned short port;
|
||||||
size_t ulen, passlen;
|
size_t ulen, passlen;
|
||||||
|
|
||||||
struct hostent *host;
|
struct hostent *host;
|
||||||
struct upstream *cur_upstream = connptr->upstream_proxy;
|
struct upstream *cur_upstream = connptr->upstream_proxy;
|
||||||
|
|
||||||
ulen = cur_upstream->ua.user ? strlen (cur_upstream->ua.user) : 0;
|
ulen = cur_upstream->ua.user ? strlen (cur_upstream->ua.user) : 0;
|
||||||
passlen = cur_upstream->pass ? strlen (cur_upstream->pass) : 0;
|
passlen = cur_upstream->pass ? strlen (cur_upstream->pass) : 0;
|
||||||
|
|
||||||
log_message (LOG_CONN,
|
log_message (LOG_CONN,
|
||||||
"Established connection to %s proxy \"%s\" using file descriptor %d.",
|
"Established connection to %s proxy \"%s\" using file descriptor %d.",
|
||||||
proxy_type_name (cur_upstream->type), cur_upstream->host,
|
proxy_type_name (cur_upstream->type), cur_upstream->host,
|
||||||
connptr->server_fd);
|
connptr->server_fd);
|
||||||
|
|
||||||
if (cur_upstream->type == PT_SOCKS4) {
|
if (cur_upstream->type == PT_SOCKS4) {
|
||||||
|
|
||||||
buff[0] = 4; /* socks version */
|
buff[0] = 4; /* socks version */
|
||||||
buff[1] = 1; /* connect command */
|
buff[1] = 1; /* connect command */
|
||||||
port = htons (request->port);
|
port = htons (request->port);
|
||||||
memcpy (&buff[2], &port, 2); /* dest port */
|
memcpy (&buff[2], &port, 2); /* dest port */
|
||||||
host = gethostbyname (request->host);
|
host = gethostbyname (request->host);
|
||||||
memcpy (&buff[4], host->h_addr_list[0], 4); /* dest ip */
|
memcpy (&buff[4], host->h_addr_list[0], 4); /* dest ip */
|
||||||
buff[8] = 0; /* user */
|
buff[8] = 0; /* user */
|
||||||
if (9 != safe_write (connptr->server_fd, buff, 9))
|
if (9 != safe_write (connptr->server_fd, buff, 9))
|
||||||
return -1;
|
return -1;
|
||||||
if (8 != safe_read (connptr->server_fd, buff, 8))
|
if (8 != safe_read (connptr->server_fd, buff, 8))
|
||||||
return -1;
|
return -1;
|
||||||
if (buff[0] != 0 || buff[1] != 90)
|
if (buff[0] != 0 || buff[1] != 90)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
} else if (cur_upstream->type == PT_SOCKS5) {
|
} else if (cur_upstream->type == PT_SOCKS5) {
|
||||||
|
|
||||||
/* init */
|
/* init */
|
||||||
int n_methods = ulen ? 2 : 1;
|
int n_methods = ulen ? 2 : 1;
|
||||||
@ -1518,7 +1520,8 @@ connect_to_upstream (struct conn_s *connptr, struct request_s *request)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_request_entity (struct conn_s *connptr)
|
static int
|
||||||
|
get_request_entity (struct conn_s *connptr)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
fd_set rset;
|
fd_set rset;
|
||||||
@ -1533,9 +1536,9 @@ static int get_request_entity (struct conn_s *connptr)
|
|||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
log_message (LOG_ERR,
|
log_message (LOG_ERR,
|
||||||
"Error calling select on client fd %d: %s",
|
"Error calling select on client fd %d: %s",
|
||||||
connptr->client_fd, strerror (errno));
|
connptr->client_fd, strerror(errno));
|
||||||
} else if (ret == 0) {
|
} else if (ret == 0) {
|
||||||
log_message (LOG_INFO, "no entity");
|
log_message (LOG_INFO, "no entity");
|
||||||
} else if (ret == 1 && FD_ISSET (connptr->client_fd, &rset)) {
|
} else if (ret == 1 && FD_ISSET (connptr->client_fd, &rset)) {
|
||||||
ssize_t nread;
|
ssize_t nread;
|
||||||
nread = read_buffer (connptr->client_fd, connptr->cbuffer);
|
nread = read_buffer (connptr->client_fd, connptr->cbuffer);
|
||||||
@ -1546,7 +1549,8 @@ static int get_request_entity (struct conn_s *connptr)
|
|||||||
ret = -1;
|
ret = -1;
|
||||||
} else {
|
} else {
|
||||||
log_message (LOG_INFO,
|
log_message (LOG_INFO,
|
||||||
"Read request entity of %d bytes", nread);
|
"Read request entity of %d bytes",
|
||||||
|
nread);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1568,7 +1572,7 @@ static int get_request_entity (struct conn_s *connptr)
|
|||||||
* tinyproxy code, which was confusing, redundant. Hail progress.
|
* tinyproxy code, which was confusing, redundant. Hail progress.
|
||||||
* - rjkaes
|
* - rjkaes
|
||||||
*/
|
*/
|
||||||
void handle_connection (int fd)
|
void handle_connection (int fd, union sockaddr_union* addr)
|
||||||
{
|
{
|
||||||
ssize_t i;
|
ssize_t i;
|
||||||
struct conn_s *connptr;
|
struct conn_s *connptr;
|
||||||
@ -1577,26 +1581,39 @@ void handle_connection (int fd)
|
|||||||
|
|
||||||
char sock_ipaddr[IP_LENGTH];
|
char sock_ipaddr[IP_LENGTH];
|
||||||
char peer_ipaddr[IP_LENGTH];
|
char peer_ipaddr[IP_LENGTH];
|
||||||
char peer_string[HOSTNAME_LENGTH];
|
|
||||||
|
|
||||||
getpeer_information (fd, peer_ipaddr, peer_string);
|
getpeer_information (addr, peer_ipaddr, sizeof(peer_ipaddr));
|
||||||
|
|
||||||
if (config.bindsame)
|
if (config.bindsame)
|
||||||
getsock_ip (fd, sock_ipaddr);
|
getsock_ip (fd, sock_ipaddr);
|
||||||
|
|
||||||
log_message (LOG_CONN, config.bindsame ?
|
log_message (LOG_CONN, config.bindsame ?
|
||||||
"Connect (file descriptor %d): %s [%s] at [%s]" :
|
"Connect (file descriptor %d): %s at [%s]" :
|
||||||
"Connect (file descriptor %d): %s [%s]",
|
"Connect (file descriptor %d): %s",
|
||||||
fd, peer_string, peer_ipaddr, sock_ipaddr);
|
fd, peer_ipaddr, sock_ipaddr);
|
||||||
|
|
||||||
connptr = initialize_conn (fd, peer_ipaddr, peer_string,
|
connptr = initialize_conn (fd, peer_ipaddr,
|
||||||
config.bindsame ? sock_ipaddr : NULL);
|
config.bindsame ? sock_ipaddr : NULL);
|
||||||
if (!connptr) {
|
if (!connptr) {
|
||||||
close (fd);
|
close (fd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_acl (peer_ipaddr, peer_string, config.access_list) <= 0) {
|
if (connection_loops (addr)) {
|
||||||
|
log_message (LOG_CONN,
|
||||||
|
"Prevented endless loop (file descriptor %d): %s",
|
||||||
|
fd, peer_ipaddr);
|
||||||
|
|
||||||
|
indicate_http_error(connptr, 400, "Bad Request",
|
||||||
|
"detail",
|
||||||
|
"You tried to connect to the "
|
||||||
|
"machine the proxy is running on",
|
||||||
|
NULL);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (check_acl (peer_ipaddr, addr, config.access_list) <= 0) {
|
||||||
update_stats (STAT_DENIED);
|
update_stats (STAT_DENIED);
|
||||||
indicate_http_error (connptr, 403, "Access denied",
|
indicate_http_error (connptr, 403, "Access denied",
|
||||||
"detail",
|
"detail",
|
||||||
@ -1647,44 +1664,34 @@ void handle_connection (int fd)
|
|||||||
ssize_t len;
|
ssize_t len;
|
||||||
char *authstring;
|
char *authstring;
|
||||||
int failure = 1, stathost_connect = 0;
|
int failure = 1, stathost_connect = 0;
|
||||||
len =
|
len = hashmap_entry_by_key (hashofheaders, "proxy-authorization",
|
||||||
hashmap_entry_by_key (hashofheaders, "proxy-authorization",
|
(void **) &authstring);
|
||||||
(void **) &authstring);
|
|
||||||
|
|
||||||
if (len == 0 && config.stathost) {
|
if (len == 0 && config.stathost) {
|
||||||
len = hashmap_entry_by_key (hashofheaders, "host",
|
len = hashmap_entry_by_key (hashofheaders, "host",
|
||||||
(void **) &authstring);
|
(void **) &authstring);
|
||||||
if (len
|
if (len && !strncmp (authstring, config.stathost, strlen(config.stathost))) {
|
||||||
&& !strncmp (authstring, config.stathost,
|
len = hashmap_entry_by_key (hashofheaders, "authorization",
|
||||||
strlen (config.stathost))) {
|
(void **) &authstring);
|
||||||
len =
|
|
||||||
hashmap_entry_by_key (hashofheaders,
|
|
||||||
"authorization",
|
|
||||||
(void **)
|
|
||||||
&authstring);
|
|
||||||
stathost_connect = 1;
|
stathost_connect = 1;
|
||||||
} else
|
} else len = 0;
|
||||||
len = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
if (stathost_connect)
|
if (stathost_connect) goto e401;
|
||||||
goto e401;
|
|
||||||
update_stats (STAT_DENIED);
|
update_stats (STAT_DENIED);
|
||||||
indicate_http_error (connptr, 407,
|
indicate_http_error (connptr, 407, "Proxy Authentication Required",
|
||||||
"Proxy Authentication Required",
|
|
||||||
"detail",
|
"detail",
|
||||||
"This proxy requires authentication.",
|
"This proxy requires authentication.",
|
||||||
NULL);
|
NULL);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if ( /* currently only "basic" auth supported */
|
if ( /* currently only "basic" auth supported */
|
||||||
(strncmp (authstring, "Basic ", 6) == 0 ||
|
(strncmp (authstring, "Basic ", 6) == 0 ||
|
||||||
strncmp (authstring, "basic ", 6) == 0) &&
|
strncmp (authstring, "basic ", 6) == 0) &&
|
||||||
basicauth_check (config.basicauth_list,
|
basicauth_check (config.basicauth_list, authstring + 6) == 1)
|
||||||
authstring + 6) == 1)
|
failure = 0;
|
||||||
failure = 0;
|
if(failure) {
|
||||||
if (failure) {
|
|
||||||
e401:
|
e401:
|
||||||
update_stats (STAT_DENIED);
|
update_stats (STAT_DENIED);
|
||||||
indicate_http_error (connptr, 401, "Unauthorized",
|
indicate_http_error (connptr, 401, "Unauthorized",
|
||||||
@ -1703,7 +1710,7 @@ e401:
|
|||||||
*/
|
*/
|
||||||
for (i = 0; i < vector_length (config.add_headers); i++) {
|
for (i = 0; i < vector_length (config.add_headers); i++) {
|
||||||
http_header_t *header = (http_header_t *)
|
http_header_t *header = (http_header_t *)
|
||||||
vector_getentry (config.add_headers, i, NULL);
|
vector_getentry (config.add_headers, i, NULL);
|
||||||
|
|
||||||
hashmap_insert (hashofheaders,
|
hashmap_insert (hashofheaders,
|
||||||
header->name,
|
header->name,
|
||||||
@ -1749,7 +1756,7 @@ e401:
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!connptr->connect_method || UPSTREAM_IS_HTTP (connptr)) {
|
if (!connptr->connect_method || UPSTREAM_IS_HTTP(connptr)) {
|
||||||
if (process_server_headers (connptr) < 0) {
|
if (process_server_headers (connptr) < 0) {
|
||||||
update_stats (STAT_BADCONN);
|
update_stats (STAT_BADCONN);
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -1781,7 +1788,8 @@ fail:
|
|||||||
* to send our data properly.
|
* to send our data properly.
|
||||||
*/
|
*/
|
||||||
if (get_request_entity (connptr) < 0) {
|
if (get_request_entity (connptr) < 0) {
|
||||||
log_message (LOG_WARNING, "Could not retrieve request entity");
|
log_message (LOG_WARNING,
|
||||||
|
"Could not retrieve request entity");
|
||||||
indicate_http_error (connptr, 400, "Bad Request",
|
indicate_http_error (connptr, 400, "Bad Request",
|
||||||
"detail",
|
"detail",
|
||||||
"Could not retrieve the request entity "
|
"Could not retrieve the request entity "
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#define _TINYPROXY_REQS_H_
|
#define _TINYPROXY_REQS_H_
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "sock.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Port constants for HTTP (80) and SSL (443)
|
* Port constants for HTTP (80) and SSL (443)
|
||||||
@ -44,6 +45,6 @@ struct request_s {
|
|||||||
char *path;
|
char *path;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void handle_connection (int fd);
|
extern void handle_connection (int fd, union sockaddr_union* addr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -139,10 +139,13 @@ 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 (reverse->url) + 1);
|
(strlen (url) +
|
||||||
|
strlen (reverse->url) +
|
||||||
|
1);
|
||||||
strcpy (rewrite_url, reverse->url);
|
strcpy (rewrite_url, reverse->url);
|
||||||
strcat (rewrite_url, url + 1);
|
strcat (rewrite_url, url + 1);
|
||||||
|
|
||||||
|
80
src/sblist.c
Normal file
80
src/sblist.c
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
#undef _POSIX_C_SOURCE
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include "sblist.h"
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#define MY_PAGE_SIZE 4096
|
||||||
|
|
||||||
|
sblist* sblist_new(size_t itemsize, size_t blockitems) {
|
||||||
|
sblist* ret = (sblist*) malloc(sizeof(sblist));
|
||||||
|
sblist_init(ret, itemsize, blockitems);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sblist_clear(sblist* l) {
|
||||||
|
l->items = NULL;
|
||||||
|
l->capa = 0;
|
||||||
|
l->count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sblist_init(sblist* l, size_t itemsize, size_t blockitems) {
|
||||||
|
if(l) {
|
||||||
|
l->blockitems = blockitems ? blockitems : MY_PAGE_SIZE / itemsize;
|
||||||
|
l->itemsize = itemsize;
|
||||||
|
sblist_clear(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sblist_free_items(sblist* l) {
|
||||||
|
if(l) {
|
||||||
|
if(l->items) free(l->items);
|
||||||
|
sblist_clear(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sblist_free(sblist* l) {
|
||||||
|
if(l) {
|
||||||
|
sblist_free_items(l);
|
||||||
|
free(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char* sblist_item_from_index(sblist* l, size_t idx) {
|
||||||
|
return l->items + (idx * l->itemsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* sblist_get(sblist* l, size_t item) {
|
||||||
|
if(item < l->count) return (void*) sblist_item_from_index(l, item);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sblist_set(sblist* l, void* item, size_t pos) {
|
||||||
|
if(pos >= l->count) return 0;
|
||||||
|
memcpy(sblist_item_from_index(l, pos), item, l->itemsize);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sblist_grow_if_needed(sblist* l) {
|
||||||
|
char* temp;
|
||||||
|
if(l->count == l->capa) {
|
||||||
|
temp = realloc(l->items, (l->capa + l->blockitems) * l->itemsize);
|
||||||
|
if(!temp) return 0;
|
||||||
|
l->capa += l->blockitems;
|
||||||
|
l->items = temp;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sblist_add(sblist* l, void* item) {
|
||||||
|
if(!sblist_grow_if_needed(l)) return 0;
|
||||||
|
l->count++;
|
||||||
|
return sblist_set(l, item, l->count - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sblist_delete(sblist* l, size_t item) {
|
||||||
|
if (l->count && item < l->count) {
|
||||||
|
memmove(sblist_item_from_index(l, item), sblist_item_from_index(l, item + 1), (sblist_getsize(l) - (item + 1)) * l->itemsize);
|
||||||
|
l->count--;
|
||||||
|
}
|
||||||
|
}
|
92
src/sblist.h
Normal file
92
src/sblist.h
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#ifndef SBLIST_H
|
||||||
|
#define SBLIST_H
|
||||||
|
|
||||||
|
/* this file is part of libulz, as of commit 8ab361a27743aaf025323ee43b8b8876dc054fdd
|
||||||
|
modified for direct inclusion in tinyproxy, and for this purpose released under
|
||||||
|
the license of tinyproxy. */
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
/*
|
||||||
|
* simple buffer list.
|
||||||
|
*
|
||||||
|
* this thing here is basically a generic dynamic array
|
||||||
|
* will realloc after every blockitems inserts
|
||||||
|
* can store items of any size.
|
||||||
|
*
|
||||||
|
* so think of it as a by-value list, as opposed to a typical by-ref list.
|
||||||
|
* you typically use it by having some struct on the stack, and pass a pointer
|
||||||
|
* to sblist_add, which will copy the contents into its internal memory.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t itemsize;
|
||||||
|
size_t blockitems;
|
||||||
|
size_t count;
|
||||||
|
size_t capa;
|
||||||
|
char* items;
|
||||||
|
} sblist;
|
||||||
|
|
||||||
|
#define sblist_getsize(X) ((X)->count)
|
||||||
|
#define sblist_get_count(X) ((X)->count)
|
||||||
|
#define sblist_empty(X) ((X)->count == 0)
|
||||||
|
|
||||||
|
/* for dynamic style */
|
||||||
|
sblist* sblist_new(size_t itemsize, size_t blockitems);
|
||||||
|
void sblist_free(sblist* l);
|
||||||
|
|
||||||
|
/*for static style*/
|
||||||
|
void sblist_init(sblist* l, size_t itemsize, size_t blockitems);
|
||||||
|
void sblist_free_items(sblist* l);
|
||||||
|
|
||||||
|
/* accessors */
|
||||||
|
void* sblist_get(sblist* l, size_t item);
|
||||||
|
/* returns 1 on success, 0 on OOM */
|
||||||
|
int sblist_add(sblist* l, void* item);
|
||||||
|
int sblist_set(sblist* l, void* item, size_t pos);
|
||||||
|
void sblist_delete(sblist* l, size_t item);
|
||||||
|
char* sblist_item_from_index(sblist* l, size_t idx);
|
||||||
|
int sblist_grow_if_needed(sblist* l);
|
||||||
|
int sblist_insert(sblist* l, void* item, size_t pos);
|
||||||
|
/* same as sblist_add, but returns list index of new item, or -1 */
|
||||||
|
size_t sblist_addi(sblist* l, void* item);
|
||||||
|
void sblist_sort(sblist *l, int (*compar)(const void *, const void *));
|
||||||
|
/* insert element into presorted list, returns listindex of new entry or -1*/
|
||||||
|
size_t sblist_insert_sorted(sblist* l, void* o, int (*compar)(const void *, const void *));
|
||||||
|
|
||||||
|
#ifndef __COUNTER__
|
||||||
|
#define __COUNTER__ __LINE__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __sblist_concat_impl( x, y ) x##y
|
||||||
|
#define __sblist_macro_concat( x, y ) __sblist_concat_impl( x, y )
|
||||||
|
#define __sblist_iterator_name __sblist_macro_concat(sblist_iterator, __COUNTER__)
|
||||||
|
|
||||||
|
/* use with custom iterator variable */
|
||||||
|
#define sblist_iter_counter(LIST, ITER, PTR) \
|
||||||
|
for(size_t ITER = 0; (PTR = sblist_get(LIST, ITER)), ITER < sblist_getsize(LIST); ITER++)
|
||||||
|
|
||||||
|
/* use with custom iterator variable, which is predeclared */
|
||||||
|
#define sblist_iter_counter2(LIST, ITER, PTR) \
|
||||||
|
for(ITER = 0; (PTR = sblist_get(LIST, ITER)), ITER < sblist_getsize(LIST); ITER++)
|
||||||
|
|
||||||
|
/* use with custom iterator variable, which is predeclared and signed */
|
||||||
|
/* useful for a loop which can delete items from the list, and then decrease the iterator var. */
|
||||||
|
#define sblist_iter_counter2s(LIST, ITER, PTR) \
|
||||||
|
for(ITER = 0; (PTR = sblist_get(LIST, ITER)), ITER < (ssize_t) sblist_getsize(LIST); ITER++)
|
||||||
|
|
||||||
|
|
||||||
|
/* uses "magic" iterator variable */
|
||||||
|
#define sblist_iter(LIST, PTR) sblist_iter_counter(LIST, __sblist_iterator_name, PTR)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
139
src/sock.c
139
src/sock.c
@ -33,11 +33,12 @@
|
|||||||
#include "sock.h"
|
#include "sock.h"
|
||||||
#include "text.h"
|
#include "text.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
#include "loop.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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,7 +51,8 @@ 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 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;
|
struct addrinfo hints, *res, *ressave;
|
||||||
int n;
|
int n;
|
||||||
@ -66,8 +68,7 @@ static int 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,
|
"bind_socket: getaddrinfo failed for %s: ", addr, get_gai_error (n));
|
||||||
get_gai_error (n));
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,8 +101,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,13 +113,12 @@ 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",
|
"opensock: Could not retrieve address info for %s:%d: %s", host, port, get_gai_error (n));
|
||||||
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 {
|
||||||
@ -129,7 +129,8 @@ 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, res->ai_family) < 0) {
|
if (bind_socket (sockfd, bind_to,
|
||||||
|
res->ai_family) < 0) {
|
||||||
close (sockfd);
|
close (sockfd);
|
||||||
continue; /* can't bind, so try again */
|
continue; /* can't bind, so try again */
|
||||||
}
|
}
|
||||||
@ -141,8 +142,17 @@ int opensock (const char *host, int port, const char *bind_to)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connect (sockfd, res->ai_addr, res->ai_addrlen) == 0)
|
if (connect (sockfd, res->ai_addr, res->ai_addrlen) == 0) {
|
||||||
|
union sockaddr_union *p = (void*) res->ai_addr, u;
|
||||||
|
int af = res->ai_addr->sa_family;
|
||||||
|
unsigned dport = ntohs(af == AF_INET ? p->v4.sin_port : p->v6.sin6_port);
|
||||||
|
socklen_t slen = sizeof u;
|
||||||
|
if (dport == config.port) {
|
||||||
|
getsockname(sockfd, (void*)&u, &slen);
|
||||||
|
loop_records_add(&u);
|
||||||
|
}
|
||||||
break; /* success */
|
break; /* success */
|
||||||
|
}
|
||||||
|
|
||||||
close (sockfd);
|
close (sockfd);
|
||||||
} while ((res = res->ai_next) != NULL);
|
} while ((res = res->ai_next) != NULL);
|
||||||
@ -151,7 +161,8 @@ 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, port);
|
host,
|
||||||
|
port);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,13 +195,14 @@ 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;
|
||||||
@ -198,60 +210,59 @@ 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",
|
log_message(LOG_ERR, "getnameinfo failed: %s", get_gai_error (ret));
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = listen (listenfd, MAXLISTEN);
|
log_message(LOG_INFO, "listening on fd [%d]", listenfd);
|
||||||
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;
|
||||||
}
|
}
|
||||||
@ -276,8 +287,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;
|
||||||
@ -290,19 +301,21 @@ 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, port, get_gai_error (n));
|
addr,
|
||||||
|
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;
|
||||||
@ -351,27 +364,9 @@ int getsock_ip (int fd, char *ipaddr)
|
|||||||
/*
|
/*
|
||||||
* Return the peer's socket information.
|
* Return the peer's socket information.
|
||||||
*/
|
*/
|
||||||
int getpeer_information (int fd, char *ipaddr, char *string_addr)
|
void getpeer_information (union sockaddr_union* addr, char *ipaddr, size_t ipaddr_len)
|
||||||
{
|
{
|
||||||
struct sockaddr_storage sa;
|
int af = addr->v4.sin_family;
|
||||||
socklen_t salen = sizeof sa;
|
void *ipdata = af == AF_INET ? (void*)&addr->v4.sin_addr : (void*)&addr->v6.sin6_addr;
|
||||||
|
inet_ntop(af, ipdata, ipaddr, ipaddr_len);
|
||||||
assert (fd >= 0);
|
|
||||||
assert (ipaddr != NULL);
|
|
||||||
assert (string_addr != NULL);
|
|
||||||
|
|
||||||
/* Set the strings to default values */
|
|
||||||
ipaddr[0] = '\0';
|
|
||||||
strlcpy (string_addr, "[unknown]", HOSTNAME_LENGTH);
|
|
||||||
|
|
||||||
/* Look up the IP address */
|
|
||||||
if (getpeername (fd, (struct sockaddr *) &sa, &salen) != 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (get_ip_string ((struct sockaddr *) &sa, ipaddr, IP_LENGTH) == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* Get the full host name */
|
|
||||||
return getnameinfo ((struct sockaddr *) &sa, salen,
|
|
||||||
string_addr, HOSTNAME_LENGTH, NULL, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
@ -28,8 +28,14 @@
|
|||||||
|
|
||||||
#define MAXLINE (1024 * 4)
|
#define MAXLINE (1024 * 4)
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
|
|
||||||
|
union sockaddr_union {
|
||||||
|
struct sockaddr_in v4;
|
||||||
|
struct sockaddr_in6 v6;
|
||||||
|
};
|
||||||
|
|
||||||
extern int opensock (const char *host, int port, const char *bind_to);
|
extern int opensock (const char *host, int port, const char *bind_to);
|
||||||
extern int listen_sock (const char *addr, uint16_t port, vector_t listen_fds);
|
extern int listen_sock (const char *addr, uint16_t port, vector_t listen_fds);
|
||||||
|
|
||||||
@ -37,6 +43,6 @@ extern int socket_nonblocking (int sock);
|
|||||||
extern int socket_blocking (int sock);
|
extern int socket_blocking (int sock);
|
||||||
|
|
||||||
extern int getsock_ip (int fd, char *ipaddr);
|
extern int getsock_ip (int fd, char *ipaddr);
|
||||||
extern int getpeer_information (int fd, char *ipaddr, char *string_addr);
|
extern void getpeer_information (union sockaddr_union *addr, char *ipaddr, size_t ipaddr_len);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
87
src/stats.c
87
src/stats.c
@ -33,6 +33,7 @@
|
|||||||
#include "stats.h"
|
#include "stats.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
struct stat_s {
|
struct stat_s {
|
||||||
unsigned long int num_reqs;
|
unsigned long int num_reqs;
|
||||||
@ -43,14 +44,16 @@ struct stat_s {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static struct stat_s *stats;
|
static struct stat_s *stats;
|
||||||
|
static pthread_mutex_t stats_update_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
static pthread_mutex_t stats_file_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the statistics information to zero.
|
* Initialize the statistics information to zero.
|
||||||
*/
|
*/
|
||||||
void init_stats (void)
|
void init_stats (void)
|
||||||
{
|
{
|
||||||
stats = (struct stat_s *) malloc_shared_memory (sizeof (struct stat_s));
|
stats = (struct stat_s *) safemalloc (sizeof (struct stat_s));
|
||||||
if (stats == MAP_FAILED)
|
if (!stats)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memset (stats, 0, sizeof (struct stat_s));
|
memset (stats, 0, sizeof (struct stat_s));
|
||||||
@ -59,7 +62,8 @@ void init_stats (void)
|
|||||||
/*
|
/*
|
||||||
* Display the statics of the tinyproxy server.
|
* Display the statics of the tinyproxy server.
|
||||||
*/
|
*/
|
||||||
int showstats (struct conn_s *connptr)
|
int
|
||||||
|
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];
|
||||||
@ -71,45 +75,51 @@ int showstats (struct conn_s *connptr)
|
|||||||
snprintf (denied, sizeof (denied), "%lu", stats->num_denied);
|
snprintf (denied, sizeof (denied), "%lu", stats->num_denied);
|
||||||
snprintf (refused, sizeof (refused), "%lu", stats->num_refused);
|
snprintf (refused, sizeof (refused), "%lu", stats->num_refused);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&stats_file_lock);
|
||||||
|
|
||||||
if (!config.statpage || (!(statfile = fopen (config.statpage, "r")))) {
|
if (!config.statpage || (!(statfile = fopen (config.statpage, "r")))) {
|
||||||
message_buffer = (char *) safemalloc (MAXBUFFSIZE);
|
message_buffer = (char *) safemalloc (MAXBUFFSIZE);
|
||||||
if (!message_buffer)
|
if (!message_buffer) {
|
||||||
return -1;
|
err_minus_one:
|
||||||
|
pthread_mutex_unlock(&stats_file_lock);
|
||||||
snprintf
|
|
||||||
(message_buffer, MAXBUFFSIZE,
|
|
||||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
|
|
||||||
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" "
|
|
||||||
"\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
|
|
||||||
"<html>\n"
|
|
||||||
"<head><title>%s version %s run-time statistics</title></head>\n"
|
|
||||||
"<body>\n"
|
|
||||||
"<h1>%s version %s run-time statistics</h1>\n"
|
|
||||||
"<p>\n"
|
|
||||||
"Number of open connections: %lu<br />\n"
|
|
||||||
"Number of requests: %lu<br />\n"
|
|
||||||
"Number of bad connections: %lu<br />\n"
|
|
||||||
"Number of denied connections: %lu<br />\n"
|
|
||||||
"Number of refused connections due to high load: %lu\n"
|
|
||||||
"</p>\n"
|
|
||||||
"<hr />\n"
|
|
||||||
"<p><em>Generated by %s version %s.</em></p>\n" "</body>\n"
|
|
||||||
"</html>\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) {
|
|
||||||
safefree (message_buffer);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
snprintf
|
||||||
|
(message_buffer, MAXBUFFSIZE,
|
||||||
|
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
|
||||||
|
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" "
|
||||||
|
"\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
|
||||||
|
"<html>\n"
|
||||||
|
"<head><title>%s version %s run-time statistics</title></head>\n"
|
||||||
|
"<body>\n"
|
||||||
|
"<h1>%s version %s run-time statistics</h1>\n"
|
||||||
|
"<p>\n"
|
||||||
|
"Number of open connections: %lu<br />\n"
|
||||||
|
"Number of requests: %lu<br />\n"
|
||||||
|
"Number of bad connections: %lu<br />\n"
|
||||||
|
"Number of denied connections: %lu<br />\n"
|
||||||
|
"Number of refused connections due to high load: %lu\n"
|
||||||
|
"</p>\n"
|
||||||
|
"<hr />\n"
|
||||||
|
"<p><em>Generated by %s version %s.</em></p>\n" "</body>\n"
|
||||||
|
"</html>\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) {
|
||||||
|
safefree (message_buffer);
|
||||||
|
goto err_minus_one;
|
||||||
|
}
|
||||||
|
|
||||||
safefree (message_buffer);
|
safefree (message_buffer);
|
||||||
|
pthread_mutex_unlock(&stats_file_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
add_error_variable (connptr, "opens", opens);
|
add_error_variable (connptr, "opens", opens);
|
||||||
add_error_variable (connptr, "reqs", reqs);
|
add_error_variable (connptr, "reqs", reqs);
|
||||||
add_error_variable (connptr, "badconns", badconns);
|
add_error_variable (connptr, "badconns", badconns);
|
||||||
@ -119,6 +129,7 @@ int showstats (struct conn_s *connptr)
|
|||||||
send_http_headers (connptr, 200, "Statistic requested");
|
send_http_headers (connptr, 200, "Statistic requested");
|
||||||
send_html_file (statfile, connptr);
|
send_html_file (statfile, connptr);
|
||||||
fclose (statfile);
|
fclose (statfile);
|
||||||
|
pthread_mutex_unlock(&stats_file_lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -129,6 +140,9 @@ int showstats (struct conn_s *connptr)
|
|||||||
*/
|
*/
|
||||||
int update_stats (status_t update_level)
|
int update_stats (status_t update_level)
|
||||||
{
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&stats_update_lock);
|
||||||
switch (update_level) {
|
switch (update_level) {
|
||||||
case STAT_BADCONN:
|
case STAT_BADCONN:
|
||||||
++stats->num_badcons;
|
++stats->num_badcons;
|
||||||
@ -147,8 +161,9 @@ int update_stats (status_t update_level)
|
|||||||
++stats->num_denied;
|
++stats->num_denied;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
|
pthread_mutex_unlock(&stats_update_lock);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
230
src/upstream.c
230
src/upstream.c
@ -31,7 +31,7 @@
|
|||||||
#include "basicauth.h"
|
#include "basicauth.h"
|
||||||
|
|
||||||
#ifdef UPSTREAM_SUPPORT
|
#ifdef UPSTREAM_SUPPORT
|
||||||
static const char *proxy_list_name (struct upstream_proxy_list *plist)
|
static const char *proxy_list_string (struct upstream_proxy_list *plist)
|
||||||
{
|
{
|
||||||
#define MAXBUF ((size_t)(1024 * 96))
|
#define MAXBUF ((size_t)(1024 * 96))
|
||||||
static char hostport[MAXBUF];
|
static char hostport[MAXBUF];
|
||||||
@ -50,6 +50,100 @@ static const char *proxy_list_name (struct upstream_proxy_list *plist)
|
|||||||
return pbuffer;
|
return pbuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* return 1 if IP string is valid, else return 0 */
|
||||||
|
static int is_valid_ip (const char *str)
|
||||||
|
{
|
||||||
|
int num, ret = 0, dots = 0;
|
||||||
|
char *ptr, *ip_str;
|
||||||
|
|
||||||
|
if (str == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ip_str = safestrdup (str);
|
||||||
|
ptr = strtok (ip_str, ".");
|
||||||
|
|
||||||
|
if (ptr == NULL)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
while (ptr) {
|
||||||
|
char *dptr = ptr;
|
||||||
|
|
||||||
|
/* after parsing string, it must contain only digits */
|
||||||
|
while (*dptr) {
|
||||||
|
if (*dptr >= '0' && *dptr <= '9')
|
||||||
|
++dptr;
|
||||||
|
else
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
num = atoi (ptr);
|
||||||
|
|
||||||
|
/* check for valid IP */
|
||||||
|
if (num >= 0 && num <= 255) {
|
||||||
|
/* parse remaining string */
|
||||||
|
ptr = strtok (NULL, ".");
|
||||||
|
if (ptr != NULL)
|
||||||
|
++dots;
|
||||||
|
} else
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* valid IP string must contain 3 dots */
|
||||||
|
if (dots != 3)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = 1;
|
||||||
|
cleanup:
|
||||||
|
safefree (ip_str);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *get_hostip (int *lookup_err, char *host, in_addr_t ip,
|
||||||
|
in_addr_t mask)
|
||||||
|
{
|
||||||
|
char *hostip;
|
||||||
|
|
||||||
|
hostip = host;
|
||||||
|
|
||||||
|
if (!is_valid_ip (host)) { /* resolve host and check ip */
|
||||||
|
int ret;
|
||||||
|
struct addrinfo *res, *ressave;
|
||||||
|
|
||||||
|
res = NULL;
|
||||||
|
ret = getaddrinfo (host, NULL, NULL, &res);
|
||||||
|
ressave = res;
|
||||||
|
if (ret != 0) {
|
||||||
|
*lookup_err = ret;
|
||||||
|
if (ret == EAI_SYSTEM)
|
||||||
|
log_message (LOG_ERR,
|
||||||
|
"get_hostip: Could not retrieve address info for %s: %s",
|
||||||
|
host, strerror (errno));
|
||||||
|
else
|
||||||
|
log_message (LOG_ERR,
|
||||||
|
"get_hostip: Could not retrieve address info for %s: %s",
|
||||||
|
host, gai_strerror (ret));
|
||||||
|
} else {
|
||||||
|
do {
|
||||||
|
struct in_addr tmp;
|
||||||
|
struct sockaddr_in *stmp;
|
||||||
|
stmp = (struct sockaddr_in *) (res->ai_addr);
|
||||||
|
tmp = stmp->sin_addr;
|
||||||
|
|
||||||
|
if ((ntohl (inet_addr (inet_ntoa (tmp))) & mask)
|
||||||
|
== ip) {
|
||||||
|
/* return if IP matches */
|
||||||
|
hostip = inet_ntoa (tmp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while ((res = res->ai_next) != NULL);
|
||||||
|
}
|
||||||
|
if (ressave)
|
||||||
|
freeaddrinfo (ressave);
|
||||||
|
}
|
||||||
|
return safestrdup (hostip);
|
||||||
|
}
|
||||||
|
|
||||||
const char *proxy_type_name (proxy_type type)
|
const char *proxy_type_name (proxy_type type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -140,7 +234,7 @@ static struct upstream *upstream_build (const struct upstream_proxy_list *plist,
|
|||||||
!strncasecmp (domain, "regexei(", 8)))) { /* extended regex case insenstive */
|
!strncasecmp (domain, "regexei(", 8)))) { /* extended regex case insenstive */
|
||||||
rflag = 1;
|
rflag = 1;
|
||||||
rptr = domain + 8;
|
rptr = domain + 8;
|
||||||
cflags |= REG_ICASE;
|
cflags |= REG_EXTENDED;
|
||||||
cflags |= REG_ICASE;
|
cflags |= REG_ICASE;
|
||||||
}
|
}
|
||||||
if (rflag) {
|
if (rflag) {
|
||||||
@ -182,7 +276,7 @@ static struct upstream *upstream_build (const struct upstream_proxy_list *plist,
|
|||||||
|
|
||||||
log_message (LOG_INFO, "Added upstream %s %s for [default]",
|
log_message (LOG_INFO, "Added upstream %s %s for [default]",
|
||||||
proxy_type_name (type),
|
proxy_type_name (type),
|
||||||
proxy_list_name (up->plist));
|
proxy_list_string (up->plist));
|
||||||
} else if (plist == NULL || type == PT_NONE) {
|
} 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,
|
||||||
@ -197,31 +291,46 @@ static struct upstream *upstream_build (const struct upstream_proxy_list *plist,
|
|||||||
struct in_addr addrstruct;
|
struct in_addr addrstruct;
|
||||||
|
|
||||||
*ptr = '\0';
|
*ptr = '\0';
|
||||||
if (inet_aton (domain, &addrstruct) != 0) {
|
if (is_valid_ip (domain)) {
|
||||||
up->ip = ntohl (addrstruct.s_addr);
|
if (inet_aton (domain, &addrstruct) !=
|
||||||
*ptr++ = '/';
|
0) {
|
||||||
|
up->ip =
|
||||||
|
ntohl (addrstruct.s_addr);
|
||||||
|
*ptr++ = '/';
|
||||||
|
|
||||||
if (strchr (ptr, '.')) {
|
if (is_valid_ip (ptr)) {
|
||||||
if (inet_aton (ptr, &addrstruct)
|
if (inet_aton
|
||||||
!= 0)
|
(ptr, &addrstruct)
|
||||||
|
!= 0)
|
||||||
|
up->mask =
|
||||||
|
ntohl
|
||||||
|
(addrstruct.
|
||||||
|
s_addr);
|
||||||
|
} else if (atoi (ptr) < 33
|
||||||
|
&& atoi (ptr) > -1) {
|
||||||
up->mask =
|
up->mask =
|
||||||
ntohl
|
~((1 <<
|
||||||
(addrstruct.s_addr);
|
(32 -
|
||||||
} else {
|
atoi (ptr))) -
|
||||||
up->mask =
|
1);
|
||||||
~((1 << (32 - atoi (ptr))) -
|
} else {
|
||||||
1);
|
up->domain =
|
||||||
|
safestrdup (domain);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
*ptr++ = '/';
|
||||||
|
up->domain = safestrdup (domain);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
up->domain = safestrdup (domain);
|
up->domain = safestrdup (domain);
|
||||||
}
|
}
|
||||||
#ifdef UPSTREAM_REGEX
|
#ifdef UPSTREAM_REGEX
|
||||||
} else {
|
} else {
|
||||||
int err = 0;
|
int ret = 0;
|
||||||
up->cpat = (regex_t *) safemalloc (sizeof (regex_t));
|
up->cpat = (regex_t *) safemalloc (sizeof (regex_t));
|
||||||
err = regcomp (up->cpat, up->pat, cflags);
|
ret = regcomp (up->cpat, up->pat, cflags);
|
||||||
if (err != 0) {
|
if (ret != 0) {
|
||||||
log_message (LOG_WARNING,
|
log_message (LOG_WARNING,
|
||||||
"Bad regex: %s", up->pat);
|
"Bad regex: %s", up->pat);
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -242,10 +351,10 @@ static struct upstream *upstream_build (const struct upstream_proxy_list *plist,
|
|||||||
up->domain = safestrdup (domain);
|
up->domain = safestrdup (domain);
|
||||||
#ifdef UPSTREAM_REGEX
|
#ifdef UPSTREAM_REGEX
|
||||||
if (rflag) {
|
if (rflag) {
|
||||||
int err = 0;
|
int ret = 0;
|
||||||
up->cpat = (regex_t *) safemalloc (sizeof (regex_t));
|
up->cpat = (regex_t *) safemalloc (sizeof (regex_t));
|
||||||
err = regcomp (up->cpat, up->pat, cflags);
|
ret = regcomp (up->cpat, up->pat, cflags);
|
||||||
if (err != 0) {
|
if (ret != 0) {
|
||||||
log_message (LOG_WARNING,
|
log_message (LOG_WARNING,
|
||||||
"Bad regex: %s", up->pat);
|
"Bad regex: %s", up->pat);
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -254,7 +363,7 @@ static struct upstream *upstream_build (const struct upstream_proxy_list *plist,
|
|||||||
#endif
|
#endif
|
||||||
log_message (LOG_INFO, "Added upstream %s %s for %s",
|
log_message (LOG_INFO, "Added upstream %s %s for %s",
|
||||||
proxy_type_name (type),
|
proxy_type_name (type),
|
||||||
proxy_list_name (up->plist), domain);
|
proxy_list_string (up->plist), domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
return up;
|
return up;
|
||||||
@ -285,14 +394,16 @@ fail:
|
|||||||
/*
|
/*
|
||||||
* Add an entry to the upstream list
|
* Add an entry to the upstream list
|
||||||
*/
|
*/
|
||||||
void upstream_add (const struct upstream_proxy_list *plist, const char *domain,
|
void upstream_add (const struct upstream_proxy_list *plist,
|
||||||
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)
|
||||||
{
|
{
|
||||||
struct upstream *up;
|
struct upstream *up;
|
||||||
struct upstream_proxy_list *upp;
|
struct upstream_proxy_list *upp;
|
||||||
|
|
||||||
up = upstream_build (plist, domain, user, pass, type);
|
up = upstream_build (plist, domain, user, pass, type);
|
||||||
|
|
||||||
if (up == NULL) {
|
if (up == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -351,10 +462,30 @@ upstream_cleanup:
|
|||||||
struct upstream *upstream_get (struct request_s *request, struct upstream *up)
|
struct upstream *upstream_get (struct request_s *request, struct upstream *up)
|
||||||
{
|
{
|
||||||
char *host = request->host;
|
char *host = request->host;
|
||||||
|
int lookup_err;
|
||||||
|
|
||||||
in_addr_t my_ip = INADDR_NONE;
|
in_addr_t my_ip = INADDR_NONE;
|
||||||
|
lookup_err = 0;
|
||||||
|
|
||||||
|
DEBUG2 ("Given url %s", request->url ? request->url : "NULL");
|
||||||
|
DEBUG2 ("Given host %s", request->host);
|
||||||
while (up) {
|
while (up) {
|
||||||
|
DEBUG2 ("Upstream type: %s\n", proxy_type_name (up->type));
|
||||||
|
#ifdef UPSTREAM_REGEX
|
||||||
|
DEBUG2 (, "Check against pattern: %s\n",
|
||||||
|
up->pat ? up->pat : "NULL");
|
||||||
|
#endif
|
||||||
|
DEBUG2 (, "Check against domain: %s\n",
|
||||||
|
up->domain ? up->domain : "NULL");
|
||||||
|
if (up->ip && up->mask) {
|
||||||
|
struct in_addr tmp1, tmp2;
|
||||||
|
tmp1.s_addr = htonl (up->ip);
|
||||||
|
tmp2.s_addr = htonl (up->mask);
|
||||||
|
DEBUG2 ("Check against ip/mask: %s/%s\n",
|
||||||
|
inet_ntoa (tmp1), inet_ntoa (tmp2));
|
||||||
|
} else {
|
||||||
|
DEBUG2 ("Check against ip/mask: NO\n");
|
||||||
|
}
|
||||||
#ifdef UPSTREAM_REGEX
|
#ifdef UPSTREAM_REGEX
|
||||||
if (up->cpat) {
|
if (up->cpat) {
|
||||||
int result;
|
int result;
|
||||||
@ -362,40 +493,69 @@ struct upstream *upstream_get (struct request_s *request, struct upstream *up)
|
|||||||
result =
|
result =
|
||||||
regexec (up->cpat, url, (size_t) 0,
|
regexec (up->cpat, url, (size_t) 0,
|
||||||
(regmatch_t *) 0, 0);
|
(regmatch_t *) 0, 0);
|
||||||
|
if (up->type == PT_NONE && result == 0) {
|
||||||
|
up = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
break; /* regex match */
|
break; /* regex match */
|
||||||
} else if (up->domain) {
|
} else if (up->domain) {
|
||||||
#else
|
#else
|
||||||
if (up->domain) {
|
if (up->domain) {
|
||||||
#endif
|
#endif
|
||||||
if (strcasecmp (host, up->domain) == 0)
|
if (strcasecmp (host, up->domain) == 0) {
|
||||||
|
if (up->type == PT_NONE)
|
||||||
|
up = NULL;
|
||||||
break; /* exact match */
|
break; /* exact match */
|
||||||
|
}
|
||||||
|
|
||||||
if (up->domain[0] == '.') {
|
if (up->domain[0] == '.') {
|
||||||
char *dot = strchr (host, '.');
|
char *dot = strchr (host, '.');
|
||||||
|
|
||||||
if (!dot && !up->domain[1])
|
if (!dot && !up->domain[1]) {
|
||||||
|
if (up->type == PT_NONE)
|
||||||
|
up = NULL;
|
||||||
break; /* local host matches "." */
|
break; /* local host matches "." */
|
||||||
|
}
|
||||||
|
|
||||||
while (dot && strcasecmp (dot, up->domain))
|
while (dot && strcasecmp (dot, up->domain))
|
||||||
dot = strchr (dot + 1, '.');
|
dot = strchr (dot + 1, '.');
|
||||||
|
|
||||||
if (dot)
|
if (dot) {
|
||||||
|
if (up->type == PT_NONE)
|
||||||
|
up = NULL;
|
||||||
break; /* subdomain match */
|
break; /* subdomain match */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (up->ip) {
|
} else if (up->ip && up->mask) {
|
||||||
if (my_ip == INADDR_NONE)
|
char *hostip = NULL;
|
||||||
my_ip = ntohl (inet_addr (host));
|
|
||||||
|
|
||||||
if ((my_ip & up->mask) == up->ip)
|
if (!lookup_err) {
|
||||||
break;
|
hostip =
|
||||||
|
get_hostip (&lookup_err, host, up->ip,
|
||||||
|
up->mask);
|
||||||
|
|
||||||
|
if (is_valid_ip (hostip)) {
|
||||||
|
if (my_ip == INADDR_NONE)
|
||||||
|
my_ip =
|
||||||
|
ntohl (inet_addr (hostip));
|
||||||
|
|
||||||
|
if ((my_ip & up->mask) == up->ip) {
|
||||||
|
if (up->type == PT_NONE)
|
||||||
|
up = NULL;
|
||||||
|
safefree (hostip);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
safefree (hostip);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
break; /* No domain or IP, default upstream */
|
break; /* No domain or IP, default upstream */
|
||||||
}
|
}
|
||||||
|
|
||||||
up = up->next;
|
up = up->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (up && !up->plist)
|
if (up && !up->plist)
|
||||||
up = NULL;
|
up = NULL;
|
||||||
|
|
||||||
@ -403,7 +563,7 @@ struct upstream *upstream_get (struct request_s *request, struct upstream *up)
|
|||||||
log_message (LOG_INFO,
|
log_message (LOG_INFO,
|
||||||
"Found upstream proxy/proxies %s %s for %s",
|
"Found upstream proxy/proxies %s %s for %s",
|
||||||
proxy_type_name (up->type),
|
proxy_type_name (up->type),
|
||||||
proxy_list_name (up->plist), host);
|
proxy_list_string (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);
|
||||||
|
|
||||||
|
@ -185,7 +185,8 @@ 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 pidfile_create (const char *filename)
|
int
|
||||||
|
pidfile_create (const char *filename)
|
||||||
{
|
{
|
||||||
int fildes;
|
int fildes;
|
||||||
FILE *fd;
|
FILE *fd;
|
||||||
|
@ -111,7 +111,10 @@ typedef enum {
|
|||||||
} vector_pos_t;
|
} vector_pos_t;
|
||||||
|
|
||||||
static int
|
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;
|
struct vectorentry_s *entry;
|
||||||
|
|
||||||
|
@ -84,10 +84,6 @@ Logfile "$TINYPROXY_LOG_DIR/tinyproxy.log"
|
|||||||
PidFile "$TINYPROXY_PID_FILE"
|
PidFile "$TINYPROXY_PID_FILE"
|
||||||
LogLevel Info
|
LogLevel Info
|
||||||
MaxClients 100
|
MaxClients 100
|
||||||
MinSpareServers 5
|
|
||||||
MaxSpareServers 20
|
|
||||||
StartServers 10
|
|
||||||
MaxRequestsPerChild 0
|
|
||||||
Allow 127.0.0.0/8
|
Allow 127.0.0.0/8
|
||||||
ViaProxyName "tinyproxy"
|
ViaProxyName "tinyproxy"
|
||||||
#DisableViaHeader Yes
|
#DisableViaHeader Yes
|
||||||
|
Loading…
Reference in New Issue
Block a user