Reformat code to GNU coding style

This is a commit which simply ran all C source code files
through GNU indent. No other modifications were made.
master
Mukund Sivaraman 2008-12-01 15:01:11 +00:00
parent 448c19077c
commit a257703e59
47 changed files with 4909 additions and 4566 deletions

447
src/acl.c
View File

@ -33,23 +33,27 @@
/* Define how long an IPv6 address is in bytes (128 bits, 16 bytes) */ /* Define how long an IPv6 address is in bytes (128 bits, 16 bytes) */
#define IPV6_LEN 16 #define IPV6_LEN 16
enum acl_type { ACL_STRING, ACL_NUMERIC }; enum acl_type
{ ACL_STRING, ACL_NUMERIC };
/* /*
* Hold the information about a particular access control. We store * Hold the information about a particular access control. We store
* whether it's an ALLOW or DENY entry, and also whether it's a string * whether it's an ALLOW or DENY entry, and also whether it's a string
* entry (like a domain name) or an IP entry. * entry (like a domain name) or an IP entry.
*/ */
struct acl_s { struct acl_s
acl_access_t access; {
enum acl_type type; acl_access_t access;
union { enum acl_type type;
char *string; union
struct { {
unsigned char octet[IPV6_LEN]; char *string;
unsigned char mask[IPV6_LEN]; struct
} ip; {
} address; unsigned char octet[IPV6_LEN];
unsigned char mask[IPV6_LEN];
} ip;
} address;
}; };
/* /*
@ -67,41 +71,45 @@ static vector_t access_list = NULL;
* *
*/ */
inline static int inline static int
fill_netmask_array(char *bitmask_string, unsigned char array[], unsigned int len) fill_netmask_array (char *bitmask_string, unsigned char array[],
unsigned int len)
{ {
unsigned int i; unsigned int i;
long int mask; long int mask;
char *endptr; char *endptr;
errno = 0; /* to distinguish success/failure after call */ errno = 0; /* to distinguish success/failure after call */
mask = strtol(bitmask_string, &endptr, 10); mask = strtol (bitmask_string, &endptr, 10);
/* check for various conversion errors */ /* check for various conversion errors */
if ((errno == ERANGE && (mask == LONG_MIN || mask == LONG_MAX)) if ((errno == ERANGE && (mask == LONG_MIN || mask == LONG_MAX))
|| (errno != 0 && mask == 0) || (errno != 0 && mask == 0) || (endptr == bitmask_string))
|| (endptr == bitmask_string)) return -1;
return -1;
/* valid range for a bit mask */ /* valid range for a bit mask */
if (mask < 0 || mask > (8 * len)) if (mask < 0 || mask > (8 * len))
return -1; return -1;
/* we have a valid range to fill in the array */ /* we have a valid range to fill in the array */
for (i = 0; i != len; ++i) { for (i = 0; i != len; ++i)
if (mask >= 8) { {
array[i] = 0xff; if (mask >= 8)
mask -= 8; {
} array[i] = 0xff;
else if (mask > 0) { mask -= 8;
array[i] = (unsigned char)(0xff << (8 - mask)); }
mask = 0; else if (mask > 0)
} {
else { array[i] = (unsigned char) (0xff << (8 - mask));
array[i] = 0; mask = 0;
} }
} else
{
array[i] = 0;
}
}
return 0; return 0;
} }
@ -115,74 +123,82 @@ fill_netmask_array(char *bitmask_string, unsigned char array[], unsigned int len
* 0 otherwise. * 0 otherwise.
*/ */
int int
insert_acl(char *location, acl_access_t access_type) insert_acl (char *location, acl_access_t access_type)
{ {
struct acl_s acl; struct acl_s acl;
int ret; int ret;
char *p, ip_dst[IPV6_LEN]; char *p, ip_dst[IPV6_LEN];
assert(location != NULL); assert (location != NULL);
/* /*
* If the access list has not been set up, create it. * If the access list has not been set up, create it.
*/ */
if (!access_list) { if (!access_list)
access_list = vector_create(); {
if (!access_list) { access_list = vector_create ();
log_message(LOG_ERR, if (!access_list)
"Unable to allocate memory for access list"); {
return -1; log_message (LOG_ERR, "Unable to allocate memory for access list");
} return -1;
} }
}
/* /*
* Start populating the access control structure. * Start populating the access control structure.
*/ */
memset(&acl, 0, sizeof(struct acl_s)); memset (&acl, 0, sizeof (struct acl_s));
acl.access = access_type; acl.access = access_type;
/* /*
* Check for a valid IP address (the simplest case) first. * Check for a valid IP address (the simplest case) first.
*/ */
if (full_inet_pton(location, ip_dst) > 0) { if (full_inet_pton (location, ip_dst) > 0)
acl.type = ACL_NUMERIC; {
memcpy(acl.address.ip.octet, ip_dst, IPV6_LEN); acl.type = ACL_NUMERIC;
memset(acl.address.ip.mask, 0xff, IPV6_LEN); memcpy (acl.address.ip.octet, ip_dst, IPV6_LEN);
} else { memset (acl.address.ip.mask, 0xff, IPV6_LEN);
/* }
* At this point we're either a hostname or an else
* IP address with a slash. {
*/ /*
p = strchr(location, '/'); * At this point we're either a hostname or an
if (p != NULL) { * IP address with a slash.
/* */
* We have a slash, so it's intended to be an p = strchr (location, '/');
* IP address with mask if (p != NULL)
*/ {
*p = '\0'; /*
if (full_inet_pton(location, ip_dst) <= 0) * We have a slash, so it's intended to be an
return -1; * IP address with mask
*/
*p = '\0';
if (full_inet_pton (location, ip_dst) <= 0)
return -1;
acl.type = ACL_NUMERIC; acl.type = ACL_NUMERIC;
memcpy(acl.address.ip.octet, ip_dst, IPV6_LEN); memcpy (acl.address.ip.octet, ip_dst, IPV6_LEN);
if (fill_netmask_array(p + 1, &(acl.address.ip.mask[0]), IPV6_LEN) < 0) if (fill_netmask_array (p + 1, &(acl.address.ip.mask[0]), IPV6_LEN)
return -1; < 0)
} else { return -1;
/* In all likelihood a string */ }
acl.type = ACL_STRING; else
acl.address.string = safestrdup(location); {
if (!acl.address.string) /* In all likelihood a string */
return -1; acl.type = ACL_STRING;
} acl.address.string = safestrdup (location);
} if (!acl.address.string)
return -1;
}
}
/* /*
* Add the entry and then clean up. * Add the entry and then clean up.
*/ */
ret = vector_append(access_list, &acl, sizeof(struct acl_s)); ret = vector_append (access_list, &acl, sizeof (struct acl_s));
safefree(acl.address.string); safefree (acl.address.string);
return ret; return ret;
} }
/* /*
@ -195,73 +211,79 @@ insert_acl(char *location, acl_access_t access_type)
* -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 *string_address) const char *ip_address, const char *string_address)
{ {
int match; int match;
struct addrinfo hints, *res, *ressave; struct addrinfo hints, *res, *ressave;
size_t test_length, match_length; size_t test_length, match_length;
char ipbuf[512]; char ipbuf[512];
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); 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
* do a string based test only; otherwise, we can do a reverse * do a string based test only; otherwise, we can do a reverse
* lookup test as well. * lookup test as well.
*/ */
if (acl->address.string[0] != '.') { if (acl->address.string[0] != '.')
memset(&hints, 0, sizeof(struct addrinfo)); {
hints.ai_family = AF_UNSPEC; memset (&hints, 0, sizeof (struct addrinfo));
hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC;
if (getaddrinfo(acl->address.string, NULL, &hints, &res) != 0) hints.ai_socktype = SOCK_STREAM;
goto STRING_TEST; if (getaddrinfo (acl->address.string, NULL, &hints, &res) != 0)
goto STRING_TEST;
ressave = res; ressave = res;
match = FALSE; match = FALSE;
do { do
get_ip_string(res->ai_addr, ipbuf, sizeof(ipbuf)); {
if (strcmp(ip_address, ipbuf) == 0) { get_ip_string (res->ai_addr, ipbuf, sizeof (ipbuf));
match = TRUE; if (strcmp (ip_address, ipbuf) == 0)
break; {
} match = TRUE;
} while ((res = res->ai_next) != NULL); break;
}
}
while ((res = res->ai_next) != NULL);
freeaddrinfo(ressave); freeaddrinfo (ressave);
if (match) { if (match)
if (acl->access == ACL_DENY) {
return 0; if (acl->access == ACL_DENY)
else return 0;
return 1; else
} return 1;
} }
}
STRING_TEST: STRING_TEST:
test_length = strlen(string_address); test_length = strlen (string_address);
match_length = strlen(acl->address.string); match_length = strlen (acl->address.string);
/* /*
* If the string length is shorter than AC string, return a -1 so * If the string length is shorter than AC string, return a -1 so
* that the "driver" will skip onto the next control in the list. * that the "driver" will skip onto the next control in the list.
*/ */
if (test_length < match_length) if (test_length < match_length)
return -1; return -1;
if (strcasecmp if (strcasecmp
(string_address + (test_length - match_length), (string_address + (test_length - match_length),
acl->address.string) == 0) { acl->address.string) == 0)
if (acl->access == ACL_DENY) {
return 0; if (acl->access == ACL_DENY)
else return 0;
return 1; else
} return 1;
}
/* Indicate that no tests succeeded, so skip to next control. */ /* Indicate that no tests succeeded, so skip to next control. */
return -1; return -1;
} }
/* /*
@ -273,28 +295,29 @@ acl_string_processing(struct acl_s *acl,
* -1 neither allowed nor denied. * -1 neither allowed nor denied.
*/ */
static int static int
check_numeric_acl(const struct acl_s *acl, const char *ip) check_numeric_acl (const struct acl_s *acl, const char *ip)
{ {
uint8_t addr[IPV6_LEN], x, y; uint8_t addr[IPV6_LEN], x, y;
int i; int i;
assert(acl && acl->type == ACL_NUMERIC); assert (acl && acl->type == ACL_NUMERIC);
assert(ip && strlen(ip) > 0); assert (ip && strlen (ip) > 0);
if (full_inet_pton(ip, &addr) <= 0) if (full_inet_pton (ip, &addr) <= 0)
return -1; return -1;
for (i = 0; i != IPV6_LEN; ++i) { for (i = 0; i != IPV6_LEN; ++i)
x = addr[i] & acl->address.ip.mask[i]; {
y = acl->address.ip.octet[i] & acl->address.ip.mask[i]; x = addr[i] & acl->address.ip.mask[i];
y = acl->address.ip.octet[i] & acl->address.ip.mask[i];
/* If x and y don't match, the IP addresses don't match */ /* If x and y don't match, the IP addresses don't match */
if (x != y) if (x != y)
return 0; return 0;
} }
/* The addresses match, return the permission */ /* The addresses match, return the permission */
return (acl->access == ACL_ALLOW); return (acl->access == ACL_ALLOW);
} }
/* /*
@ -305,50 +328,52 @@ check_numeric_acl(const struct acl_s *acl, const char *ip)
* 0 if denied * 0 if denied
*/ */
int int
check_acl(int fd, const char *ip, const char *host) check_acl (int fd, const char *ip, const char *host)
{ {
struct acl_s *acl; struct acl_s *acl;
int perm; int perm;
size_t i; size_t i;
assert(fd >= 0); assert (fd >= 0);
assert(ip != NULL); assert (ip != NULL);
assert(host != NULL); assert (host != NULL);
/* /*
* If there is no access list allow everything. * If there is no access list allow everything.
*/ */
if (!access_list) if (!access_list)
return 1; return 1;
for (i = 0; i != vector_length(access_list); ++i) { for (i = 0; i != vector_length (access_list); ++i)
acl = vector_getentry(access_list, i, NULL); {
switch (acl->type) { acl = vector_getentry (access_list, i, NULL);
case ACL_STRING: switch (acl->type)
perm = acl_string_processing(acl, ip, host); {
break; case ACL_STRING:
perm = acl_string_processing (acl, ip, host);
break;
case ACL_NUMERIC: case ACL_NUMERIC:
if (ip[0] == '\0') if (ip[0] == '\0')
continue; continue;
perm = check_numeric_acl(acl, ip); perm = check_numeric_acl (acl, ip);
break; break;
} }
/* /*
* Check the return value too see if the IP address is * Check the return value too see if the IP address is
* allowed or denied. * allowed or denied.
*/ */
if (perm == 0) if (perm == 0)
break; break;
else if (perm == 1) else if (perm == 1)
return perm; return perm;
} }
/* /*
* 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\" [%s].",
host, ip); host, ip);
return 0; return 0;
} }

View File

@ -21,10 +21,11 @@
#ifndef TINYPROXY_ACL_H #ifndef TINYPROXY_ACL_H
#define TINYPROXY_ACL_H #define TINYPROXY_ACL_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);
extern int check_acl(int fd, const char *ip_address, extern int check_acl (int fd, const char *ip_address,
const char *string_address); const char *string_address);
#endif #endif

View File

@ -30,9 +30,9 @@
static hashmap_t anonymous_map = NULL; static hashmap_t anonymous_map = NULL;
short int short int
is_anonymous_enabled(void) is_anonymous_enabled (void)
{ {
return (anonymous_map != NULL) ? 1 : 0; return (anonymous_map != NULL) ? 1 : 0;
} }
/* /*
@ -40,12 +40,12 @@ is_anonymous_enabled(void)
* zero if the string was found, zero if it wasn't and negative upon error. * zero if the string was found, zero if it wasn't and negative upon error.
*/ */
int int
anonymous_search(char *s) anonymous_search (char *s)
{ {
assert(s != NULL); assert (s != NULL);
assert(anonymous_map != NULL); assert (anonymous_map != NULL);
return hashmap_search(anonymous_map, s); return hashmap_search (anonymous_map, s);
} }
/* /*
@ -55,23 +55,25 @@ anonymous_search(char *s)
* successful. * successful.
*/ */
int int
anonymous_insert(char *s) anonymous_insert (char *s)
{ {
char data = 1; char data = 1;
assert(s != NULL); assert (s != NULL);
if (!anonymous_map) { if (!anonymous_map)
anonymous_map = hashmap_create(32); {
if (!anonymous_map) anonymous_map = hashmap_create (32);
return -1; if (!anonymous_map)
} return -1;
}
if (hashmap_search(anonymous_map, s) > 0) { if (hashmap_search (anonymous_map, s) > 0)
/* The key was already found, so return a positive number. */ {
return 0; /* The key was already found, so return a positive number. */
} return 0;
}
/* Insert the new key */ /* Insert the new key */
return hashmap_insert(anonymous_map, s, &data, sizeof(data)); return hashmap_insert (anonymous_map, s, &data, sizeof (data));
} }

View File

@ -21,8 +21,8 @@
#ifndef _TINYPROXY_ANONYMOUS_H_ #ifndef _TINYPROXY_ANONYMOUS_H_
#define _TINYPROXY_ANONYMOUS_H_ #define _TINYPROXY_ANONYMOUS_H_
extern short int is_anonymous_enabled(void); extern short int is_anonymous_enabled (void);
extern int anonymous_search(char *s); extern int anonymous_search (char *s);
extern int anonymous_insert(char *s); extern int anonymous_insert (char *s);
#endif #endif

View File

@ -34,21 +34,23 @@
#define BUFFER_HEAD(x) (x)->head #define BUFFER_HEAD(x) (x)->head
#define BUFFER_TAIL(x) (x)->tail #define BUFFER_TAIL(x) (x)->tail
struct bufline_s { struct bufline_s
unsigned char *string; /* the actual string of data */ {
struct bufline_s *next; /* pointer to next in linked list */ unsigned char *string; /* the actual string of data */
size_t length; /* length of the string of data */ struct bufline_s *next; /* pointer to next in linked list */
size_t pos; /* start sending from this offset */ size_t length; /* length of the string of data */
size_t pos; /* start sending from this offset */
}; };
/* /*
* The buffer structure points to the beginning and end of the buffer list * The buffer structure points to the beginning and end of the buffer list
* (and includes the total size) * (and includes the total size)
*/ */
struct buffer_s { struct buffer_s
struct bufline_s *head; /* top of the buffer */ {
struct bufline_s *tail; /* bottom of the buffer */ struct bufline_s *head; /* top of the buffer */
size_t size; /* total size of the buffer */ struct bufline_s *tail; /* bottom of the buffer */
size_t size; /* total size of the buffer */
}; };
/* /*
@ -57,155 +59,158 @@ struct buffer_s {
* data buffer on the heap, delete it because you now have TWO copies. * data buffer on the heap, delete it because you now have TWO copies.
*/ */
static struct bufline_s * static struct bufline_s *
makenewline(unsigned char *data, size_t length) makenewline (unsigned char *data, size_t length)
{ {
struct bufline_s *newline; struct bufline_s *newline;
assert(data != NULL); assert (data != NULL);
assert(length > 0); assert (length > 0);
if (!(newline = safemalloc(sizeof(struct bufline_s)))) if (!(newline = safemalloc (sizeof (struct bufline_s))))
return NULL; return NULL;
if (!(newline->string = safemalloc(length))) { if (!(newline->string = safemalloc (length)))
safefree(newline); {
return NULL; safefree (newline);
} return NULL;
}
memcpy(newline->string, data, length); memcpy (newline->string, data, length);
newline->next = NULL; newline->next = NULL;
newline->length = length; newline->length = length;
/* Position our "read" pointer at the beginning of the data */ /* Position our "read" pointer at the beginning of the data */
newline->pos = 0; newline->pos = 0;
return newline; return newline;
} }
/* /*
* Free the allocated buffer line * Free the allocated buffer line
*/ */
static void static void
free_line(struct bufline_s *line) free_line (struct bufline_s *line)
{ {
assert(line != NULL); assert (line != NULL);
if (!line) if (!line)
return; return;
if (line->string) if (line->string)
safefree(line->string); safefree (line->string);
safefree(line); safefree (line);
} }
/* /*
* Create a new buffer * Create a new buffer
*/ */
struct buffer_s * struct buffer_s *
new_buffer(void) new_buffer (void)
{ {
struct buffer_s *buffptr; struct buffer_s *buffptr;
if (!(buffptr = safemalloc(sizeof(struct buffer_s)))) if (!(buffptr = safemalloc (sizeof (struct buffer_s))))
return NULL; return NULL;
/* /*
* Since the buffer is initially empty, set the HEAD and TAIL * Since the buffer is initially empty, set the HEAD and TAIL
* pointers to NULL since they can't possibly point anywhere at the * pointers to NULL since they can't possibly point anywhere at the
* moment. * moment.
*/ */
BUFFER_HEAD(buffptr) = BUFFER_TAIL(buffptr) = NULL; BUFFER_HEAD (buffptr) = BUFFER_TAIL (buffptr) = NULL;
buffptr->size = 0; buffptr->size = 0;
return buffptr; return buffptr;
} }
/* /*
* Delete all the lines in the buffer and the buffer itself * Delete all the lines in the buffer and the buffer itself
*/ */
void void
delete_buffer(struct buffer_s *buffptr) delete_buffer (struct buffer_s *buffptr)
{ {
struct bufline_s *next; struct bufline_s *next;
assert(buffptr != NULL); assert (buffptr != NULL);
while (BUFFER_HEAD(buffptr)) { while (BUFFER_HEAD (buffptr))
next = BUFFER_HEAD(buffptr)->next; {
free_line(BUFFER_HEAD(buffptr)); next = BUFFER_HEAD (buffptr)->next;
BUFFER_HEAD(buffptr) = next; free_line (BUFFER_HEAD (buffptr));
} BUFFER_HEAD (buffptr) = next;
}
safefree(buffptr); safefree (buffptr);
} }
/* /*
* Return the current size of the buffer. * Return the current size of the buffer.
*/ */
size_t size_t
buffer_size(struct buffer_s *buffptr) buffer_size (struct buffer_s *buffptr)
{ {
return buffptr->size; return buffptr->size;
} }
/* /*
* Push a new line on to the end of the buffer. * Push a new line on to the end of the buffer.
*/ */
int int
add_to_buffer(struct buffer_s *buffptr, unsigned char *data, size_t length) add_to_buffer (struct buffer_s *buffptr, unsigned char *data, size_t length)
{ {
struct bufline_s *newline; struct bufline_s *newline;
assert(buffptr != NULL); assert (buffptr != NULL);
assert(data != NULL); assert (data != NULL);
assert(length > 0); assert (length > 0);
/* /*
* Sanity check here. A buffer with a non-NULL head pointer must * Sanity check here. A buffer with a non-NULL head pointer must
* have a size greater than zero, and vice-versa. * have a size greater than zero, and vice-versa.
*/ */
if (BUFFER_HEAD(buffptr) == NULL) if (BUFFER_HEAD (buffptr) == NULL)
assert(buffptr->size == 0); assert (buffptr->size == 0);
else else
assert(buffptr->size > 0); assert (buffptr->size > 0);
/* /*
* Make a new line so we can add it to the buffer. * Make a new line so we can add it to the buffer.
*/ */
if (!(newline = makenewline(data, length))) if (!(newline = makenewline (data, length)))
return -1; return -1;
if (buffptr->size == 0) if (buffptr->size == 0)
BUFFER_HEAD(buffptr) = BUFFER_TAIL(buffptr) = newline; BUFFER_HEAD (buffptr) = BUFFER_TAIL (buffptr) = newline;
else { else
BUFFER_TAIL(buffptr)->next = newline; {
BUFFER_TAIL(buffptr) = newline; BUFFER_TAIL (buffptr)->next = newline;
} BUFFER_TAIL (buffptr) = newline;
}
buffptr->size += length; buffptr->size += length;
return 0; return 0;
} }
/* /*
* Remove the first line from the top of the buffer * Remove the first line from the top of the buffer
*/ */
static struct bufline_s * static struct bufline_s *
remove_from_buffer(struct buffer_s *buffptr) remove_from_buffer (struct buffer_s *buffptr)
{ {
struct bufline_s *line; struct bufline_s *line;
assert(buffptr != NULL); assert (buffptr != NULL);
assert(BUFFER_HEAD(buffptr) != NULL); assert (BUFFER_HEAD (buffptr) != NULL);
line = BUFFER_HEAD(buffptr); line = BUFFER_HEAD (buffptr);
BUFFER_HEAD(buffptr) = line->next; BUFFER_HEAD (buffptr) = line->next;
buffptr->size -= line->length; buffptr->size -= line->length;
return line; return line;
} }
/* /*
@ -214,61 +219,69 @@ remove_from_buffer(struct buffer_s *buffptr)
*/ */
#define READ_BUFFER_SIZE (1024 * 2) #define READ_BUFFER_SIZE (1024 * 2)
ssize_t ssize_t
read_buffer(int fd, struct buffer_s * buffptr) read_buffer (int fd, struct buffer_s * buffptr)
{ {
ssize_t bytesin; ssize_t bytesin;
unsigned char *buffer; unsigned char *buffer;
assert(fd >= 0); assert (fd >= 0);
assert(buffptr != NULL); assert (buffptr != NULL);
/* /*
* Don't allow the buffer to grow larger than MAXBUFFSIZE * Don't allow the buffer to grow larger than MAXBUFFSIZE
*/ */
if (buffptr->size >= MAXBUFFSIZE) if (buffptr->size >= MAXBUFFSIZE)
return 0; return 0;
buffer = safemalloc(READ_BUFFER_SIZE); buffer = safemalloc (READ_BUFFER_SIZE);
if (!buffer) { if (!buffer)
return -ENOMEM; {
} return -ENOMEM;
}
bytesin = read(fd, buffer, READ_BUFFER_SIZE); bytesin = read (fd, buffer, READ_BUFFER_SIZE);
if (bytesin > 0) { if (bytesin > 0)
if (add_to_buffer(buffptr, buffer, bytesin) < 0) { {
log_message(LOG_ERR, if (add_to_buffer (buffptr, buffer, bytesin) < 0)
"readbuff: add_to_buffer() error."); {
bytesin = -1; log_message (LOG_ERR, "readbuff: add_to_buffer() error.");
} bytesin = -1;
} else { }
if (bytesin == 0) { }
/* connection was closed by client */ else
bytesin = -1; {
} else { if (bytesin == 0)
switch (errno) { {
/* connection was closed by client */
bytesin = -1;
}
else
{
switch (errno)
{
#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;
break; break;
default: default:
log_message(LOG_ERR, log_message (LOG_ERR,
"readbuff: recv() error \"%s\" on file descriptor %d", "readbuff: recv() error \"%s\" on file descriptor %d",
strerror(errno), fd); strerror (errno), fd);
bytesin = -1; bytesin = -1;
break; break;
} }
} }
} }
safefree(buffer); safefree (buffer);
return bytesin; return bytesin;
} }
/* /*
@ -276,53 +289,57 @@ read_buffer(int fd, struct buffer_s * buffptr)
* Takes a connection and returns the number of bytes written. * Takes a connection and returns the number of bytes written.
*/ */
ssize_t ssize_t
write_buffer(int fd, struct buffer_s * buffptr) write_buffer (int fd, struct buffer_s * buffptr)
{ {
ssize_t bytessent; ssize_t bytessent;
struct bufline_s *line; struct bufline_s *line;
assert(fd >= 0); assert (fd >= 0);
assert(buffptr != NULL); assert (buffptr != NULL);
if (buffptr->size == 0) if (buffptr->size == 0)
return 0; return 0;
/* Sanity check. It would be bad to be using a NULL pointer! */ /* Sanity check. It would be bad to be using a NULL pointer! */
assert(BUFFER_HEAD(buffptr) != NULL); assert (BUFFER_HEAD (buffptr) != NULL);
line = BUFFER_HEAD(buffptr); line = BUFFER_HEAD (buffptr);
bytessent = bytessent =
send(fd, line->string + line->pos, line->length - line->pos, send (fd, line->string + line->pos, line->length - line->pos,
MSG_NOSIGNAL); MSG_NOSIGNAL);
if (bytessent >= 0) { if (bytessent >= 0)
/* bytes sent, adjust buffer */ {
line->pos += bytessent; /* bytes sent, adjust buffer */
if (line->pos == line->length) line->pos += bytessent;
free_line(remove_from_buffer(buffptr)); if (line->pos == line->length)
return bytessent; free_line (remove_from_buffer (buffptr));
} else { return bytessent;
switch (errno) { }
else
{
switch (errno)
{
#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;
case ENOBUFS: case ENOBUFS:
case ENOMEM: case ENOMEM:
log_message(LOG_ERR, log_message (LOG_ERR,
"writebuff: write() error [NOBUFS/NOMEM] \"%s\" on file descriptor %d", "writebuff: write() error [NOBUFS/NOMEM] \"%s\" on file descriptor %d",
strerror(errno), fd); strerror (errno), fd);
return 0; return 0;
default: default:
log_message(LOG_ERR, log_message (LOG_ERR,
"writebuff: write() error \"%s\" on file descriptor %d", "writebuff: write() error \"%s\" on file descriptor %d",
strerror(errno), fd); strerror (errno), fd);
return -1; return -1;
} }
} }
} }

View File

@ -24,17 +24,17 @@
/* Forward declaration */ /* Forward declaration */
struct buffer_s; struct buffer_s;
extern struct buffer_s *new_buffer(void); extern struct buffer_s *new_buffer (void);
extern void delete_buffer(struct buffer_s *buffptr); extern void delete_buffer (struct buffer_s *buffptr);
extern size_t buffer_size(struct buffer_s *buffptr); extern size_t buffer_size (struct buffer_s *buffptr);
/* /*
* Add a new line to the given buffer. The data IS copied into the structure. * Add a new line to the given buffer. The data IS copied into the structure.
*/ */
extern int add_to_buffer(struct buffer_s *buffptr, unsigned char *data, extern int add_to_buffer (struct buffer_s *buffptr, unsigned char *data,
size_t length); size_t length);
extern ssize_t read_buffer(int fd, struct buffer_s *buffptr); extern ssize_t read_buffer (int fd, struct buffer_s *buffptr);
extern ssize_t write_buffer(int fd, struct buffer_s *buffptr); extern ssize_t write_buffer (int fd, struct buffer_s *buffptr);
#endif /* __BUFFER_H_ */ #endif /* __BUFFER_H_ */

View File

@ -37,11 +37,13 @@ static socklen_t addrlen;
/* /*
* Stores the internal data needed for each child (connection) * Stores the internal data needed for each child (connection)
*/ */
enum child_status_t { T_EMPTY, T_WAITING, T_CONNECTED }; enum child_status_t
struct child_s { { T_EMPTY, T_WAITING, T_CONNECTED };
pid_t tid; struct child_s
unsigned int connects; {
enum child_status_t status; pid_t tid;
unsigned int connects;
enum child_status_t status;
}; };
/* /*
@ -50,12 +52,13 @@ struct child_s {
*/ */
static struct child_s *child_ptr; static struct child_s *child_ptr;
static struct child_config_s { static struct child_config_s
int maxclients, maxrequestsperchild; {
int maxspareservers, minspareservers, startservers; int maxclients, maxrequestsperchild;
int maxspareservers, minspareservers, startservers;
} child_config; } child_config;
static unsigned int *servers_waiting; /* servers waiting for a connection */ static unsigned int *servers_waiting; /* servers waiting for a connection */
/* /*
* Lock/Unlock the "servers_waiting" variable so that two children cannot * Lock/Unlock the "servers_waiting" variable so that two children cannot
@ -74,47 +77,48 @@ static struct flock lock_it, unlock_it;
static int lock_fd = -1; static int lock_fd = -1;
static void static void
_child_lock_init(void) _child_lock_init (void)
{ {
char lock_file[] = "/tmp/tinyproxy.servers.lock.XXXXXX"; char lock_file[] = "/tmp/tinyproxy.servers.lock.XXXXXX";
/* 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.
*/ */
umask(0177); umask (0177);
lock_fd = mkstemp(lock_file); lock_fd = mkstemp (lock_file);
unlink(lock_file); unlink (lock_file);
lock_it.l_type = F_WRLCK; lock_it.l_type = F_WRLCK;
lock_it.l_whence = SEEK_SET; lock_it.l_whence = SEEK_SET;
lock_it.l_start = 0; lock_it.l_start = 0;
lock_it.l_len = 0; lock_it.l_len = 0;
unlock_it.l_type = F_UNLCK; unlock_it.l_type = F_UNLCK;
unlock_it.l_whence = SEEK_SET; unlock_it.l_whence = SEEK_SET;
unlock_it.l_start = 0; unlock_it.l_start = 0;
unlock_it.l_len = 0; unlock_it.l_len = 0;
} }
static void static void
_child_lock_wait(void) _child_lock_wait (void)
{ {
int rc; int rc;
while ((rc = fcntl(lock_fd, F_SETLKW, &lock_it)) < 0) { while ((rc = fcntl (lock_fd, F_SETLKW, &lock_it)) < 0)
if (errno == EINTR) {
continue; if (errno == EINTR)
else continue;
return; else
} return;
}
} }
static void static void
_child_lock_release(void) _child_lock_release (void)
{ {
if (fcntl(lock_fd, F_SETLKW, &unlock_it) < 0) if (fcntl (lock_fd, F_SETLKW, &unlock_it) < 0)
return; return;
} }
/* END OF LOCKING SECTION */ /* END OF LOCKING SECTION */
@ -138,126 +142,133 @@ _child_lock_release(void)
* Set the configuration values for the various child related settings. * Set the configuration values for the various child related settings.
*/ */
short int short int
child_configure(child_config_t type, int val) child_configure (child_config_t type, int val)
{ {
switch (type) { switch (type)
case CHILD_MAXCLIENTS: {
child_config.maxclients = val; case CHILD_MAXCLIENTS:
break; child_config.maxclients = val;
case CHILD_MAXSPARESERVERS: break;
child_config.maxspareservers = val; case CHILD_MAXSPARESERVERS:
break; child_config.maxspareservers = val;
case CHILD_MINSPARESERVERS: break;
child_config.minspareservers = val; case CHILD_MINSPARESERVERS:
break; child_config.minspareservers = val;
case CHILD_STARTSERVERS: break;
child_config.startservers = val; case CHILD_STARTSERVERS:
break; child_config.startservers = val;
case CHILD_MAXREQUESTSPERCHILD: break;
child_config.maxrequestsperchild = val; case CHILD_MAXREQUESTSPERCHILD:
break; child_config.maxrequestsperchild = val;
default: break;
DEBUG2("Invalid type (%d)", type); default:
return -1; DEBUG2 ("Invalid type (%d)", type);
} return -1;
}
return 0; return 0;
} }
/* /*
* This is the main (per child) loop. * This is the main (per child) loop.
*/ */
static void static void
child_main(struct child_s *ptr) child_main (struct child_s *ptr)
{ {
int connfd; int connfd;
struct sockaddr *cliaddr; struct sockaddr *cliaddr;
socklen_t clilen; socklen_t clilen;
cliaddr = safemalloc(addrlen); cliaddr = safemalloc (addrlen);
if (!cliaddr) { if (!cliaddr)
log_message(LOG_CRIT, {
"Could not allocate memory for child address."); log_message (LOG_CRIT, "Could not allocate memory for child address.");
exit(0); exit (0);
} }
ptr->connects = 0; ptr->connects = 0;
while (!config.quit) { while (!config.quit)
ptr->status = T_WAITING; {
ptr->status = T_WAITING;
clilen = addrlen; clilen = addrlen;
connfd = accept(listenfd, cliaddr, &clilen); connfd = accept (listenfd, cliaddr, &clilen);
#ifndef NDEBUG #ifndef NDEBUG
/* /*
* Enable the TINYPROXY_DEBUG environment variable if you * Enable the TINYPROXY_DEBUG environment variable if you
* want to use the GDB debugger. * want to use the GDB debugger.
*/ */
if (getenv("TINYPROXY_DEBUG")) { if (getenv ("TINYPROXY_DEBUG"))
/* Pause for 10 seconds to allow us to connect debugger */ {
fprintf(stderr, /* Pause for 10 seconds to allow us to connect debugger */
"Process has accepted connection: %ld\n", fprintf (stderr,
(long int)ptr->tid); "Process has accepted connection: %ld\n",
sleep(10); (long int) ptr->tid);
fprintf(stderr, "Continuing process: %ld\n", sleep (10);
(long int)ptr->tid); fprintf (stderr, "Continuing process: %ld\n", (long int) ptr->tid);
} }
#endif #endif
/* /*
* Make sure no error occurred... * Make sure no error occurred...
*/ */
if (connfd < 0) { if (connfd < 0)
log_message(LOG_ERR, {
"Accept returned an error (%s) ... retrying.", log_message (LOG_ERR,
strerror(errno)); "Accept returned an error (%s) ... retrying.",
continue; strerror (errno));
} continue;
}
ptr->status = T_CONNECTED; ptr->status = T_CONNECTED;
SERVER_DEC(); SERVER_DEC ();
handle_connection(connfd); handle_connection (connfd);
ptr->connects++; ptr->connects++;
if (child_config.maxrequestsperchild != 0) { if (child_config.maxrequestsperchild != 0)
DEBUG2("%u connections so far...", ptr->connects); {
DEBUG2 ("%u connections so far...", ptr->connects);
if (ptr->connects == child_config.maxrequestsperchild) { if (ptr->connects == child_config.maxrequestsperchild)
log_message(LOG_NOTICE, {
"Child has reached MaxRequestsPerChild (%u). Killing child.", log_message (LOG_NOTICE,
ptr->connects); "Child has reached MaxRequestsPerChild (%u). Killing child.",
break; ptr->connects);
} break;
} }
}
SERVER_COUNT_LOCK(); SERVER_COUNT_LOCK ();
if (*servers_waiting > child_config.maxspareservers) { if (*servers_waiting > child_config.maxspareservers)
/* {
* There are too many spare children, kill ourself /*
* off. * There are too many spare children, kill ourself
*/ * off.
log_message(LOG_NOTICE, */
"Waiting servers (%d) exceeds MaxSpareServers (%d). Killing child.", log_message (LOG_NOTICE,
*servers_waiting, "Waiting servers (%d) exceeds MaxSpareServers (%d). Killing child.",
child_config.maxspareservers); *servers_waiting, child_config.maxspareservers);
SERVER_COUNT_UNLOCK(); SERVER_COUNT_UNLOCK ();
break; break;
} else { }
SERVER_COUNT_UNLOCK(); else
} {
SERVER_COUNT_UNLOCK ();
}
SERVER_INC(); SERVER_INC ();
} }
ptr->status = T_EMPTY; ptr->status = T_EMPTY;
safefree(cliaddr); safefree (cliaddr);
exit(0); exit (0);
} }
/* /*
@ -265,104 +276,113 @@ child_main(struct child_s *ptr)
* child_main() function. * child_main() function.
*/ */
static pid_t static pid_t
child_make(struct child_s *ptr) child_make (struct child_s *ptr)
{ {
pid_t pid; pid_t pid;
if ((pid = fork()) > 0) if ((pid = fork ()) > 0)
return pid; /* parent */ return pid; /* parent */
/* /*
* Reset the SIGNALS so that the child can be reaped. * Reset the SIGNALS so that the child can be reaped.
*/ */
set_signal_handler(SIGCHLD, SIG_DFL); set_signal_handler (SIGCHLD, SIG_DFL);
set_signal_handler(SIGTERM, SIG_DFL); set_signal_handler (SIGTERM, SIG_DFL);
set_signal_handler(SIGHUP, SIG_DFL); set_signal_handler (SIGHUP, SIG_DFL);
child_main(ptr); /* never returns */ child_main (ptr); /* never returns */
return -1; return -1;
} }
/* /*
* Create a pool of children to handle incoming connections * Create a pool of children to handle incoming connections
*/ */
short int short int
child_pool_create(void) child_pool_create (void)
{ {
unsigned int i; unsigned int i;
/* /*
* Make sure the number of MaxClients is not zero, since this * Make sure the number of MaxClients is not zero, since this
* variable determines the size of the array created for children * variable determines the size of the array created for children
* later on. * later on.
*/ */
if (child_config.maxclients == 0) { if (child_config.maxclients == 0)
log_message(LOG_ERR, {
"child_pool_create: \"MaxClients\" must be greater than zero."); log_message (LOG_ERR,
return -1; "child_pool_create: \"MaxClients\" must be greater than zero.");
} return -1;
if (child_config.startservers == 0) { }
log_message(LOG_ERR, if (child_config.startservers == 0)
"child_pool_create: \"StartServers\" must be greater than zero."); {
return -1; log_message (LOG_ERR,
} "child_pool_create: \"StartServers\" must be greater than zero.");
return -1;
}
child_ptr = calloc_shared_memory(child_config.maxclients, child_ptr = calloc_shared_memory (child_config.maxclients,
sizeof(struct child_s)); sizeof (struct child_s));
if (!child_ptr) { if (!child_ptr)
log_message(LOG_ERR, "Could not allocate memory for children."); {
return -1; log_message (LOG_ERR, "Could not allocate memory for children.");
} return -1;
}
servers_waiting = malloc_shared_memory(sizeof(unsigned int)); servers_waiting = malloc_shared_memory (sizeof (unsigned int));
if (servers_waiting == MAP_FAILED) { if (servers_waiting == MAP_FAILED)
log_message(LOG_ERR, {
"Could not allocate memory for child counting."); log_message (LOG_ERR, "Could not allocate memory for child counting.");
return -1; return -1;
} }
*servers_waiting = 0; *servers_waiting = 0;
/* /*
* Create a "locking" file for use around the servers_waiting * Create a "locking" file for use around the servers_waiting
* variable. * variable.
*/ */
_child_lock_init(); _child_lock_init ();
if (child_config.startservers > child_config.maxclients) { if (child_config.startservers > child_config.maxclients)
log_message(LOG_WARNING, {
"Can not start more than \"MaxClients\" servers. Starting %u servers instead.", log_message (LOG_WARNING,
child_config.maxclients); "Can not start more than \"MaxClients\" servers. Starting %u servers instead.",
child_config.startservers = child_config.maxclients; child_config.maxclients);
} child_config.startservers = child_config.maxclients;
}
for (i = 0; i != child_config.maxclients; i++) { for (i = 0; i != child_config.maxclients; i++)
child_ptr[i].status = T_EMPTY; {
child_ptr[i].connects = 0; child_ptr[i].status = T_EMPTY;
} child_ptr[i].connects = 0;
}
for (i = 0; i != child_config.startservers; i++) { for (i = 0; i != child_config.startservers; i++)
DEBUG2("Trying to create child %d of %d", i + 1, {
child_config.startservers); DEBUG2 ("Trying to create child %d of %d", i + 1,
child_ptr[i].status = T_WAITING; child_config.startservers);
child_ptr[i].tid = child_make(&child_ptr[i]); child_ptr[i].status = T_WAITING;
child_ptr[i].tid = child_make (&child_ptr[i]);
if (child_ptr[i].tid < 0) { if (child_ptr[i].tid < 0)
log_message(LOG_WARNING, {
"Could not create child number %d of %d", log_message (LOG_WARNING,
i, child_config.startservers); "Could not create child number %d of %d",
return -1; i, child_config.startservers);
} else { return -1;
log_message(LOG_INFO, }
"Creating child number %d of %d ...", else
i + 1, child_config.startservers); {
log_message (LOG_INFO,
"Creating child number %d of %d ...",
i + 1, child_config.startservers);
SERVER_INC(); SERVER_INC ();
} }
} }
log_message(LOG_INFO, "Finished creating all children."); log_message (LOG_INFO, "Finished creating all children.");
return 0; return 0;
} }
/* /*
@ -370,88 +390,95 @@ child_pool_create(void)
* servers. It monitors this at least once a second. * servers. It monitors this at least once a second.
*/ */
void void
child_main_loop(void) child_main_loop (void)
{ {
unsigned int i; unsigned int i;
while (1) { while (1)
if (config.quit) {
return; if (config.quit)
return;
/* If there are not enough spare servers, create more */ /* If there are not enough spare servers, create more */
SERVER_COUNT_LOCK(); SERVER_COUNT_LOCK ();
if (*servers_waiting < child_config.minspareservers) { if (*servers_waiting < child_config.minspareservers)
log_message(LOG_NOTICE, {
"Waiting servers (%d) is less than MinSpareServers (%d). Creating new child.", log_message (LOG_NOTICE,
*servers_waiting, "Waiting servers (%d) is less than MinSpareServers (%d). Creating new child.",
child_config.minspareservers); *servers_waiting, child_config.minspareservers);
SERVER_COUNT_UNLOCK(); SERVER_COUNT_UNLOCK ();
for (i = 0; i != child_config.maxclients; i++) { for (i = 0; i != child_config.maxclients; i++)
if (child_ptr[i].status == T_EMPTY) { {
child_ptr[i].status = T_WAITING; if (child_ptr[i].status == T_EMPTY)
child_ptr[i].tid = {
child_make(&child_ptr[i]); child_ptr[i].status = T_WAITING;
if (child_ptr[i].tid < 0) { child_ptr[i].tid = child_make (&child_ptr[i]);
log_message(LOG_NOTICE, if (child_ptr[i].tid < 0)
"Could not create child"); {
log_message (LOG_NOTICE, "Could not create child");
child_ptr[i].status = T_EMPTY; child_ptr[i].status = T_EMPTY;
break; break;
} }
SERVER_INC(); SERVER_INC ();
break; break;
} }
} }
} else { }
SERVER_COUNT_UNLOCK(); else
} {
SERVER_COUNT_UNLOCK ();
}
sleep(5); sleep (5);
/* Handle log rotation if it was requested */ /* Handle log rotation if it was requested */
if (received_sighup) { if (received_sighup)
truncate_log_file(); {
truncate_log_file ();
#ifdef FILTER_ENABLE #ifdef FILTER_ENABLE
if (config.filter) { if (config.filter)
filter_destroy(); {
filter_init(); filter_destroy ();
} filter_init ();
log_message(LOG_NOTICE, "Re-reading filter file."); }
#endif /* FILTER_ENABLE */ log_message (LOG_NOTICE, "Re-reading filter file.");
#endif /* FILTER_ENABLE */
received_sighup = FALSE; received_sighup = FALSE;
} }
} }
} }
/* /*
* Go through all the non-empty children and cancel them. * Go through all the non-empty children and cancel them.
*/ */
void void
child_kill_children(void) child_kill_children (void)
{ {
unsigned int i; unsigned int i;
for (i = 0; i != child_config.maxclients; i++) { for (i = 0; i != child_config.maxclients; i++)
if (child_ptr[i].status != T_EMPTY) {
kill(child_ptr[i].tid, SIGTERM); if (child_ptr[i].status != T_EMPTY)
} kill (child_ptr[i].tid, SIGTERM);
}
} }
int int
child_listening_sock(uint16_t port) child_listening_sock (uint16_t port)
{ {
listenfd = listen_sock(port, &addrlen); listenfd = listen_sock (port, &addrlen);
return listenfd; return listenfd;
} }
void void
child_close_sock(void) child_close_sock (void)
{ {
close(listenfd); close (listenfd);
} }

View File

@ -21,20 +21,21 @@
#ifndef TINYPROXY_CHILD_H #ifndef TINYPROXY_CHILD_H
#define TINYPROXY_CHILD_H #define TINYPROXY_CHILD_H
typedef enum { typedef enum
CHILD_MAXCLIENTS, {
CHILD_MAXSPARESERVERS, CHILD_MAXCLIENTS,
CHILD_MINSPARESERVERS, CHILD_MAXSPARESERVERS,
CHILD_STARTSERVERS, CHILD_MINSPARESERVERS,
CHILD_MAXREQUESTSPERCHILD CHILD_STARTSERVERS,
CHILD_MAXREQUESTSPERCHILD
} child_config_t; } child_config_t;
extern short int child_pool_create(void); extern short int child_pool_create (void);
extern int child_listening_sock(uint16_t port); extern int child_listening_sock (uint16_t port);
extern void child_close_sock(void); extern void child_close_sock (void);
extern void child_main_loop(void); extern void child_main_loop (void);
extern void child_kill_children(void); extern void child_kill_children (void);
extern short int child_configure(child_config_t type, int val); extern short int child_configure (child_config_t type, int val);
#endif #endif

View File

@ -173,13 +173,13 @@
# define MSG_NOSIGNAL (0) # define MSG_NOSIGNAL (0)
#endif #endif
#ifndef SHUT_RD /* these three Posix.1g names are quite new */ #ifndef SHUT_RD /* these three Posix.1g names are quite new */
# define SHUT_RD 0 /* shutdown for reading */ # define SHUT_RD 0 /* shutdown for reading */
# define SHUT_WR 1 /* shutdown for writing */ # define SHUT_WR 1 /* shutdown for writing */
# define SHUT_RDWR 2 /* shutdown for reading and writing */ # define SHUT_RDWR 2 /* shutdown for reading and writing */
#endif #endif
#define MAXLISTEN 1024 /* Max number of connections */ #define MAXLISTEN 1024 /* Max number of connections */
/* /*
* SunOS doesn't have INADDR_NONE defined. * SunOS doesn't have INADDR_NONE defined.

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,7 @@
#ifndef TINYPROXY_CONFFILE_H #ifndef TINYPROXY_CONFFILE_H
#define TINYPROXY_CONFFILE_H #define TINYPROXY_CONFFILE_H
extern int config_compile(void); extern int config_compile (void);
extern int config_parse(struct config_s *conf, FILE * f); extern int config_parse (struct config_s *conf, FILE * f);
#endif #endif

View File

@ -31,118 +31,118 @@
#include "stats.h" #include "stats.h"
struct conn_s * struct conn_s *
initialize_conn(int client_fd, const char *ipaddr, const char *string_addr, 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;
struct buffer_s *cbuffer, *sbuffer; struct buffer_s *cbuffer, *sbuffer;
assert(client_fd >= 0); assert (client_fd >= 0);
/* /*
* Allocate the memory for all the internal components * Allocate the memory for all the internal components
*/ */
cbuffer = new_buffer(); cbuffer = new_buffer ();
sbuffer = new_buffer(); sbuffer = new_buffer ();
if (!cbuffer || !sbuffer) if (!cbuffer || !sbuffer)
goto error_exit; goto error_exit;
/* /*
* Allocate the space for the conn_s structure itself. * Allocate the space for the conn_s structure itself.
*/ */
connptr = safemalloc(sizeof(struct conn_s)); connptr = safemalloc (sizeof (struct conn_s));
if (!connptr) if (!connptr)
goto error_exit; goto error_exit;
connptr->client_fd = client_fd; connptr->client_fd = client_fd;
connptr->server_fd = -1; connptr->server_fd = -1;
connptr->cbuffer = cbuffer; connptr->cbuffer = cbuffer;
connptr->sbuffer = sbuffer; connptr->sbuffer = sbuffer;
connptr->request_line = NULL; connptr->request_line = NULL;
/* These store any error strings */ /* These store any error strings */
connptr->error_variables = NULL; connptr->error_variables = NULL;
connptr->error_string = NULL; connptr->error_string = NULL;
connptr->error_number = -1; connptr->error_number = -1;
connptr->connect_method = FALSE; connptr->connect_method = FALSE;
connptr->show_stats = FALSE; connptr->show_stats = FALSE;
connptr->protocol.major = connptr->protocol.minor = 0; connptr->protocol.major = connptr->protocol.minor = 0;
/* There is _no_ content length initially */ /* There is _no_ content length initially */
connptr->content_length.server = connptr->content_length.client = -1; connptr->content_length.server = connptr->content_length.client = -1;
connptr->server_ip_addr = sock_ipaddr ? safestrdup(sock_ipaddr) : 0; connptr->server_ip_addr = sock_ipaddr ? safestrdup (sock_ipaddr) : 0;
connptr->client_ip_addr = safestrdup(ipaddr); connptr->client_ip_addr = safestrdup (ipaddr);
connptr->client_string_addr = safestrdup(string_addr); connptr->client_string_addr = safestrdup (string_addr);
connptr->upstream_proxy = NULL; connptr->upstream_proxy = NULL;
update_stats(STAT_OPEN); update_stats (STAT_OPEN);
#ifdef REVERSE_SUPPORT #ifdef REVERSE_SUPPORT
connptr->reversepath = NULL; connptr->reversepath = NULL;
#endif #endif
return connptr; return connptr;
error_exit: error_exit:
/* /*
* If we got here, there was a problem allocating memory * If we got here, there was a problem allocating memory
*/ */
if (cbuffer) if (cbuffer)
delete_buffer(cbuffer); delete_buffer (cbuffer);
if (sbuffer) if (sbuffer)
delete_buffer(sbuffer); delete_buffer (sbuffer);
return NULL; return NULL;
} }
void void
destroy_conn(struct conn_s *connptr) destroy_conn (struct conn_s *connptr)
{ {
assert(connptr != NULL); assert (connptr != NULL);
if (connptr->client_fd != -1) if (connptr->client_fd != -1)
if (close(connptr->client_fd) < 0) if (close (connptr->client_fd) < 0)
log_message(LOG_INFO, "Client (%d) close message: %s", log_message (LOG_INFO, "Client (%d) close message: %s",
connptr->client_fd, strerror(errno)); connptr->client_fd, strerror (errno));
if (connptr->server_fd != -1) if (connptr->server_fd != -1)
if (close(connptr->server_fd) < 0) if (close (connptr->server_fd) < 0)
log_message(LOG_INFO, "Server (%d) close message: %s", log_message (LOG_INFO, "Server (%d) close message: %s",
connptr->server_fd, strerror(errno)); connptr->server_fd, strerror (errno));
if (connptr->cbuffer) if (connptr->cbuffer)
delete_buffer(connptr->cbuffer); delete_buffer (connptr->cbuffer);
if (connptr->sbuffer) if (connptr->sbuffer)
delete_buffer(connptr->sbuffer); delete_buffer (connptr->sbuffer);
if (connptr->request_line) if (connptr->request_line)
safefree(connptr->request_line); safefree (connptr->request_line);
if (connptr->error_variables) if (connptr->error_variables)
hashmap_delete(connptr->error_variables); hashmap_delete (connptr->error_variables);
if (connptr->error_string) if (connptr->error_string)
safefree(connptr->error_string); safefree (connptr->error_string);
if (connptr->server_ip_addr) if (connptr->server_ip_addr)
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) if (connptr->client_string_addr)
safefree(connptr->client_string_addr); safefree (connptr->client_string_addr);
#ifdef REVERSE_SUPPORT #ifdef REVERSE_SUPPORT
if (connptr->reversepath) if (connptr->reversepath)
safefree(connptr->reversepath); safefree (connptr->reversepath);
#endif #endif
safefree(connptr); safefree (connptr);
update_stats(STAT_CLOSE); update_stats (STAT_CLOSE);
} }

View File

@ -27,73 +27,76 @@
/* /*
* Connection Definition * Connection Definition
*/ */
struct conn_s { struct conn_s
int client_fd; {
int server_fd; int client_fd;
int server_fd;
struct buffer_s *cbuffer; struct buffer_s *cbuffer;
struct buffer_s *sbuffer; struct buffer_s *sbuffer;
/* The request line (first line) from the client */ /* The request line (first line) from the client */
char *request_line; char *request_line;
/* Booleans */ /* Booleans */
unsigned int connect_method; unsigned int connect_method;
unsigned int show_stats; unsigned int show_stats;
/* /*
* This structure stores key -> value mappings for substitution * This structure stores key -> value mappings for substitution
* in the error HTML files. * in the error HTML files.
*/ */
hashmap_t error_variables; hashmap_t error_variables;
int error_number; int error_number;
char *error_string; char *error_string;
/* A Content-Length value from the remote server */ /* A Content-Length value from the remote server */
struct { struct
long int server; {
long int client; long int server;
} content_length; long int client;
} content_length;
/* /*
* Store the server's IP (for BindSame) * Store the server's IP (for BindSame)
*/ */
char *server_ip_addr; char *server_ip_addr;
/* /*
* Store the client's IP and hostname information * Store the client's IP and hostname information
*/ */
char *client_ip_addr; char *client_ip_addr;
char *client_string_addr; char *client_string_addr;
/* /*
* Store the incoming request's HTTP protocol. * Store the incoming request's HTTP protocol.
*/ */
struct { struct
unsigned int major; {
unsigned int minor; unsigned int major;
} protocol; unsigned int minor;
} protocol;
#ifdef REVERSE_SUPPORT #ifdef REVERSE_SUPPORT
/* /*
* Place to store the current per-connection reverse proxy path * Place to store the current per-connection reverse proxy path
*/ */
char *reversepath; char *reversepath;
#endif #endif
/* /*
* Pointer to upstream proxy. * Pointer to upstream proxy.
*/ */
struct upstream *upstream_proxy; struct upstream *upstream_proxy;
}; };
/* /*
* 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 *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);
#endif #endif

View File

@ -30,28 +30,28 @@
* program a daemon process. * program a daemon process.
*/ */
void void
makedaemon(void) makedaemon (void)
{ {
if (fork() != 0) if (fork () != 0)
exit(0); exit (0);
setsid(); setsid ();
set_signal_handler(SIGHUP, SIG_IGN); set_signal_handler (SIGHUP, SIG_IGN);
if (fork() != 0) if (fork () != 0)
exit(0); exit (0);
chdir("/"); chdir ("/");
umask(0177); umask (0177);
#if NDEBUG #if NDEBUG
/* /*
* When not in debugging mode, close the standard file * When not in debugging mode, close the standard file
* descriptors. * descriptors.
*/ */
close(0); close (0);
close(1); close (1);
close(2); close (2);
#endif #endif
} }
@ -60,25 +60,28 @@ makedaemon(void)
* to handle signals sent to the process. * to handle signals sent to the process.
*/ */
signal_func * signal_func *
set_signal_handler(int signo, signal_func *func) set_signal_handler (int signo, signal_func * func)
{ {
struct sigaction act, oact; struct sigaction act, oact;
act.sa_handler = func; act.sa_handler = func;
sigemptyset(&act.sa_mask); sigemptyset (&act.sa_mask);
act.sa_flags = 0; act.sa_flags = 0;
if (signo == SIGALRM) { if (signo == SIGALRM)
{
#ifdef SA_INTERRUPT #ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */ act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */
#endif #endif
} else { }
else
{
#ifdef SA_RESTART #ifdef SA_RESTART
act.sa_flags |= SA_RESTART; /* SVR4, 4.4BSD */ act.sa_flags |= SA_RESTART; /* SVR4, 4.4BSD */
#endif #endif
} }
if (sigaction(signo, &act, &oact) < 0) if (sigaction (signo, &act, &oact) < 0)
return SIG_ERR; return SIG_ERR;
return oact.sa_handler; return oact.sa_handler;
} }

View File

@ -26,11 +26,11 @@ typedef void signal_func (int);
/* /*
* Pass a singal integer and a function to handle the signal. * Pass a singal integer and a function to handle the signal.
*/ */
extern signal_func *set_signal_handler(int signo, signal_func *func); extern signal_func *set_signal_handler (int signo, signal_func * func);
/* /*
* Make a program a daemon process * Make a program a daemon process
*/ */
extern void makedaemon(void); extern void makedaemon (void);
#endif #endif

View File

@ -33,10 +33,11 @@
static int err; static int err;
struct filter_list { struct filter_list
struct filter_list *next; {
char *pat; struct filter_list *next;
regex_t *cpat; char *pat;
regex_t *cpat;
}; };
static struct filter_list *fl = NULL; static struct filter_list *fl = NULL;
@ -47,171 +48,176 @@ static filter_policy_t default_policy = FILTER_DEFAULT_ALLOW;
* Initializes a linked list of strings containing hosts/urls to be filtered * Initializes a linked list of strings containing hosts/urls to be filtered
*/ */
void void
filter_init(void) filter_init (void)
{ {
FILE *fd; FILE *fd;
struct filter_list *p; struct filter_list *p;
char buf[FILTER_BUFFER_LEN]; char buf[FILTER_BUFFER_LEN];
char *s; char *s;
int cflags; int cflags;
if (!fl && !already_init) { if (!fl && !already_init)
fd = fopen(config.filter, "r"); {
if (fd) { fd = fopen (config.filter, "r");
p = NULL; if (fd)
{
p = NULL;
cflags = REG_NEWLINE | REG_NOSUB; cflags = REG_NEWLINE | REG_NOSUB;
if (config.filter_extended) if (config.filter_extended)
cflags |= REG_EXTENDED; cflags |= REG_EXTENDED;
if (!config.filter_casesensitive) if (!config.filter_casesensitive)
cflags |= REG_ICASE; cflags |= REG_ICASE;
while (fgets(buf, FILTER_BUFFER_LEN, fd)) { while (fgets (buf, FILTER_BUFFER_LEN, fd))
/* {
* Remove any trailing white space and /*
* comments. * Remove any trailing white space and
*/ * comments.
s = buf; */
while (*s) { s = buf;
if (isspace((unsigned char)*s)) while (*s)
break; {
if (*s == '#') { if (isspace ((unsigned char) *s))
/* break;
* If the '#' char is preceeded by if (*s == '#')
* an escape, it's not a comment {
* string. /*
*/ * If the '#' char is preceeded by
if (s == buf * an escape, it's not a comment
|| *(s - 1) != '\\') * string.
break; */
} if (s == buf || *(s - 1) != '\\')
++s; break;
} }
*s = '\0'; ++s;
}
*s = '\0';
/* skip leading whitespace */ /* skip leading whitespace */
s = buf; s = buf;
while (*s && isspace((unsigned char)*s)) while (*s && isspace ((unsigned char) *s))
s++; s++;
/* skip blank lines and comments */ /* skip blank lines and comments */
if (*s == '\0') if (*s == '\0')
continue; continue;
if (!p) /* head of list */ if (!p) /* head of list */
fl = p = fl = p = safecalloc (1, sizeof (struct filter_list));
safecalloc(1, else
sizeof(struct { /* next entry */
filter_list)); p->next = safecalloc (1, sizeof (struct filter_list));
else { /* next entry */ p = p->next;
p->next = }
safecalloc(1,
sizeof(struct
filter_list));
p = p->next;
}
p->pat = safestrdup(s); p->pat = safestrdup (s);
p->cpat = safemalloc(sizeof(regex_t)); p->cpat = safemalloc (sizeof (regex_t));
if ((err = if ((err = regcomp (p->cpat, p->pat, cflags)) != 0)
regcomp(p->cpat, p->pat, cflags)) != 0) { {
fprintf(stderr, "Bad regex in %s: %s\n", fprintf (stderr, "Bad regex in %s: %s\n",
config.filter, p->pat); config.filter, p->pat);
exit(EX_DATAERR); exit (EX_DATAERR);
} }
} }
if (ferror(fd)) { if (ferror (fd))
perror("fgets"); {
exit(EX_DATAERR); perror ("fgets");
} exit (EX_DATAERR);
fclose(fd); }
fclose (fd);
already_init = 1; already_init = 1;
} }
} }
} }
/* unlink the list */ /* unlink the list */
void void
filter_destroy(void) filter_destroy (void)
{ {
struct filter_list *p, *q; struct filter_list *p, *q;
if (already_init) { if (already_init)
for (p = q = fl; p; p = q) { {
regfree(p->cpat); for (p = q = fl; p; p = q)
safefree(p->cpat); {
safefree(p->pat); regfree (p->cpat);
q = p->next; safefree (p->cpat);
safefree(p); safefree (p->pat);
} q = p->next;
fl = NULL; safefree (p);
already_init = 0; }
} fl = NULL;
already_init = 0;
}
} }
/* Return 0 to allow, non-zero to block */ /* Return 0 to allow, non-zero to block */
int int
filter_domain(const char *host) filter_domain (const char *host)
{ {
struct filter_list *p; struct filter_list *p;
int result; int result;
if (!fl || !already_init) if (!fl || !already_init)
goto COMMON_EXIT; goto COMMON_EXIT;
for (p = fl; p; p = p->next) { for (p = fl; p; p = p->next)
result = {
regexec(p->cpat, host, (size_t) 0, (regmatch_t *) 0, 0); result = regexec (p->cpat, host, (size_t) 0, (regmatch_t *) 0, 0);
if (result == 0) { if (result == 0)
if (default_policy == FILTER_DEFAULT_ALLOW) {
return 1; if (default_policy == FILTER_DEFAULT_ALLOW)
else return 1;
return 0; else
} return 0;
} }
}
COMMON_EXIT: COMMON_EXIT:
if (default_policy == FILTER_DEFAULT_ALLOW) if (default_policy == FILTER_DEFAULT_ALLOW)
return 0; return 0;
else else
return 1; return 1;
} }
/* returns 0 to allow, non-zero to block */ /* returns 0 to allow, non-zero to block */
int int
filter_url(const char *url) filter_url (const char *url)
{ {
struct filter_list *p; struct filter_list *p;
int result; int result;
if (!fl || !already_init) if (!fl || !already_init)
goto COMMON_EXIT; goto COMMON_EXIT;
for (p = fl; p; p = p->next) { for (p = fl; p; p = p->next)
result = regexec(p->cpat, url, (size_t) 0, (regmatch_t *) 0, 0); {
result = regexec (p->cpat, url, (size_t) 0, (regmatch_t *) 0, 0);
if (result == 0) { if (result == 0)
if (default_policy == FILTER_DEFAULT_ALLOW) {
return 1; if (default_policy == FILTER_DEFAULT_ALLOW)
else return 1;
return 0; else
} return 0;
} }
}
COMMON_EXIT: COMMON_EXIT:
if (default_policy == FILTER_DEFAULT_ALLOW) if (default_policy == FILTER_DEFAULT_ALLOW)
return 0; return 0;
else else
return 1; return 1;
} }
/* /*
* Set the default filtering policy * Set the default filtering policy
*/ */
void void
filter_set_default_policy(filter_policy_t policy) filter_set_default_policy (filter_policy_t policy)
{ {
default_policy = policy; default_policy = policy;
} }

View File

@ -21,16 +21,17 @@
#ifndef _TINYPROXY_FILTER_H_ #ifndef _TINYPROXY_FILTER_H_
#define _TINYPROXY_FILTER_H_ #define _TINYPROXY_FILTER_H_
typedef enum { typedef enum
FILTER_DEFAULT_ALLOW, {
FILTER_DEFAULT_DENY, FILTER_DEFAULT_ALLOW,
FILTER_DEFAULT_DENY,
} filter_policy_t; } filter_policy_t;
extern void filter_init(void); extern void filter_init (void);
extern void filter_destroy(void); extern void filter_destroy (void);
extern int filter_domain(const char *host); extern int filter_domain (const char *host);
extern int filter_url(const char *url); extern int filter_url (const char *url);
extern void filter_set_default_policy(filter_policy_t policy); extern void filter_set_default_policy (filter_policy_t policy);
#endif #endif

View File

@ -37,23 +37,26 @@
* internal use. It stores the number of buckets the hashmap was created * internal use. It stores the number of buckets the hashmap was created
* with. * with.
*/ */
struct hashentry_s { struct hashentry_s
char *key; {
void *data; char *key;
size_t len; void *data;
size_t len;
struct hashentry_s *prev, *next; struct hashentry_s *prev, *next;
}; };
struct hashbucket_s { struct hashbucket_s
struct hashentry_s *head, *tail; {
struct hashentry_s *head, *tail;
}; };
struct hashmap_s { struct hashmap_s
unsigned int size; {
hashmap_iter end_iterator; unsigned int size;
hashmap_iter end_iterator;
struct hashbucket_s *buckets; struct hashbucket_s *buckets;
}; };
/* /*
@ -66,25 +69,26 @@ struct hashmap_s {
* If any of the arguments are invalid a negative number is returned. * If any of the arguments are invalid a negative number is returned.
*/ */
static int static int
hashfunc(const char *key, unsigned int size) hashfunc (const char *key, unsigned int size)
{ {
uint32_t hash; uint32_t hash;
if (key == NULL) if (key == NULL)
return -EINVAL; return -EINVAL;
if (size == 0) if (size == 0)
return -ERANGE; return -ERANGE;
for (hash = tolower(*key++); *key != '\0'; key++) { for (hash = tolower (*key++); *key != '\0'; key++)
uint32_t bit = (hash & 1) ? (1 << (sizeof(uint32_t) - 1)) : 0; {
uint32_t bit = (hash & 1) ? (1 << (sizeof (uint32_t) - 1)) : 0;
hash >>= 1; hash >>= 1;
hash += tolower(*key) + bit; hash += tolower (*key) + bit;
} }
/* Keep the hash within the table limits */ /* Keep the hash within the table limits */
return hash % size; return hash % size;
} }
/* /*
@ -95,28 +99,29 @@ hashfunc(const char *key, unsigned int size)
* NULLs are also returned if memory could not be allocated for hashmap. * NULLs are also returned if memory could not be allocated for hashmap.
*/ */
hashmap_t hashmap_t
hashmap_create(unsigned int nbuckets) hashmap_create (unsigned int nbuckets)
{ {
struct hashmap_s *ptr; struct hashmap_s *ptr;
if (nbuckets == 0) if (nbuckets == 0)
return NULL; return NULL;
ptr = safecalloc(1, sizeof(struct hashmap_s)); ptr = safecalloc (1, sizeof (struct hashmap_s));
if (!ptr) if (!ptr)
return NULL; return NULL;
ptr->size = nbuckets; ptr->size = nbuckets;
ptr->buckets = safecalloc(nbuckets, sizeof(struct hashbucket_s)); ptr->buckets = safecalloc (nbuckets, sizeof (struct hashbucket_s));
if (!ptr->buckets) { if (!ptr->buckets)
safefree(ptr); {
return NULL; safefree (ptr);
} return NULL;
}
/* This points to "one" past the end of the hashmap. */ /* This points to "one" past the end of the hashmap. */
ptr->end_iterator = 0; ptr->end_iterator = 0;
return ptr; return ptr;
} }
/* /*
@ -127,26 +132,27 @@ hashmap_create(unsigned int nbuckets)
* negative number is returned if "entry" was NULL * negative number is returned if "entry" was NULL
*/ */
static inline int static inline int
delete_hashbucket(struct hashbucket_s *bucket) delete_hashbucket (struct hashbucket_s *bucket)
{ {
struct hashentry_s *nextptr; struct hashentry_s *nextptr;
struct hashentry_s *ptr; struct hashentry_s *ptr;
if (bucket == NULL || bucket->head == NULL) if (bucket == NULL || bucket->head == NULL)
return -EINVAL; return -EINVAL;
ptr = bucket->head; ptr = bucket->head;
while (ptr) { while (ptr)
nextptr = ptr->next; {
nextptr = ptr->next;
safefree(ptr->key); safefree (ptr->key);
safefree(ptr->data); safefree (ptr->data);
safefree(ptr); safefree (ptr);
ptr = nextptr; ptr = nextptr;
} }
return 0; return 0;
} }
/* /*
@ -156,23 +162,25 @@ delete_hashbucket(struct hashbucket_s *bucket)
* negative if a NULL "map" was supplied * negative if a NULL "map" was supplied
*/ */
int int
hashmap_delete(hashmap_t map) hashmap_delete (hashmap_t map)
{ {
unsigned int i; unsigned int i;
if (map == NULL) if (map == NULL)
return -EINVAL; return -EINVAL;
for (i = 0; i != map->size; i++) { for (i = 0; i != map->size; i++)
if (map->buckets[i].head != NULL) { {
delete_hashbucket(&map->buckets[i]); if (map->buckets[i].head != NULL)
} {
} delete_hashbucket (&map->buckets[i]);
}
}
safefree(map->buckets); safefree (map->buckets);
safefree(map); safefree (map);
return 0; return 0;
} }
/* /*
@ -186,67 +194,69 @@ hashmap_delete(hashmap_t map)
* negative number if there are errors * negative number if there are errors
*/ */
int int
hashmap_insert(hashmap_t map, const char *key, const void *data, size_t len) hashmap_insert (hashmap_t map, const char *key, const void *data, size_t len)
{ {
struct hashentry_s *ptr; struct hashentry_s *ptr;
int hash; int hash;
char *key_copy; char *key_copy;
void *data_copy; void *data_copy;
assert(map != NULL); assert (map != NULL);
assert(key != NULL); assert (key != NULL);
assert(data != NULL); assert (data != NULL);
assert(len > 0); assert (len > 0);
if (map == NULL || key == NULL) if (map == NULL || key == NULL)
return -EINVAL; return -EINVAL;
if (!data || len < 1) if (!data || len < 1)
return -ERANGE; return -ERANGE;
hash = hashfunc(key, map->size); hash = hashfunc (key, map->size);
if (hash < 0) if (hash < 0)
return hash; return hash;
/* /*
* First make copies of the key and data in case there is a memory * First make copies of the key and data in case there is a memory
* problem later. * problem later.
*/ */
key_copy = safestrdup(key); key_copy = safestrdup (key);
if (!key_copy) if (!key_copy)
return -ENOMEM; return -ENOMEM;
data_copy = safemalloc(len); data_copy = safemalloc (len);
if (!data_copy) { if (!data_copy)
safefree(key_copy); {
return -ENOMEM; safefree (key_copy);
} return -ENOMEM;
memcpy(data_copy, data, len); }
memcpy (data_copy, data, len);
ptr = safemalloc(sizeof(struct hashentry_s)); ptr = safemalloc (sizeof (struct hashentry_s));
if (!ptr) { if (!ptr)
safefree(key_copy); {
safefree(data_copy); safefree (key_copy);
return -ENOMEM; safefree (data_copy);
} return -ENOMEM;
}
ptr->key = key_copy; ptr->key = key_copy;
ptr->data = data_copy; ptr->data = data_copy;
ptr->len = len; ptr->len = len;
/* /*
* Now add the entry to the end of the bucket chain. * Now add the entry to the end of the bucket chain.
*/ */
ptr->next = NULL; ptr->next = NULL;
ptr->prev = map->buckets[hash].tail; ptr->prev = map->buckets[hash].tail;
if (map->buckets[hash].tail) if (map->buckets[hash].tail)
map->buckets[hash].tail->next = ptr; map->buckets[hash].tail->next = ptr;
map->buckets[hash].tail = ptr; map->buckets[hash].tail = ptr;
if (!map->buckets[hash].head) if (!map->buckets[hash].head)
map->buckets[hash].head = ptr; map->buckets[hash].head = ptr;
map->end_iterator++; map->end_iterator++;
return 0; return 0;
} }
/* /*
@ -255,17 +265,17 @@ hashmap_insert(hashmap_t map, const char *key, const void *data, size_t len)
* Returns: an negative value upon error. * Returns: an negative value upon error.
*/ */
hashmap_iter hashmap_iter
hashmap_first(hashmap_t map) hashmap_first (hashmap_t map)
{ {
assert(map != NULL); assert (map != NULL);
if (!map) if (!map)
return -EINVAL; return -EINVAL;
if (map->end_iterator == 0) if (map->end_iterator == 0)
return -1; return -1;
else else
return 0; return 0;
} }
/* /*
@ -275,18 +285,18 @@ hashmap_first(hashmap_t map)
* 0 otherwise * 0 otherwise
*/ */
int int
hashmap_is_end(hashmap_t map, hashmap_iter iter) hashmap_is_end (hashmap_t map, hashmap_iter iter)
{ {
assert(map != NULL); assert (map != NULL);
assert(iter >= 0); assert (iter >= 0);
if (!map || iter < 0) if (!map || iter < 0)
return -EINVAL; return -EINVAL;
if (iter == map->end_iterator) if (iter == map->end_iterator)
return 1; return 1;
else else
return 0; return 0;
} }
/* /*
@ -298,37 +308,40 @@ hashmap_is_end(hashmap_t map, hashmap_iter iter)
* an "end-iterator" if the key wasn't found * an "end-iterator" if the key wasn't found
*/ */
hashmap_iter hashmap_iter
hashmap_find(hashmap_t map, const char *key) hashmap_find (hashmap_t map, const char *key)
{ {
unsigned int i; unsigned int i;
hashmap_iter iter = 0; hashmap_iter iter = 0;
struct hashentry_s *ptr; struct hashentry_s *ptr;
assert(map != NULL); assert (map != NULL);
assert(key != NULL); assert (key != NULL);
if (!map || !key) if (!map || !key)
return -EINVAL; return -EINVAL;
/* /*
* Loop through all the keys and look for the first occurrence * Loop through all the keys and look for the first occurrence
* of a particular key. * of a particular key.
*/ */
for (i = 0; i != map->size; i++) { for (i = 0; i != map->size; i++)
ptr = map->buckets[i].head; {
ptr = map->buckets[i].head;
while (ptr) { while (ptr)
if (strcasecmp(ptr->key, key) == 0) { {
/* Found it, so return the current count */ if (strcasecmp (ptr->key, key) == 0)
return iter; {
} /* Found it, so return the current count */
return iter;
}
iter++; iter++;
ptr = ptr->next; ptr = ptr->next;
} }
} }
return iter; return iter;
} }
/* /*
@ -338,37 +351,41 @@ hashmap_find(hashmap_t map, const char *key)
* negative upon error * negative upon error
*/ */
ssize_t ssize_t
hashmap_return_entry(hashmap_t map, hashmap_iter iter, char **key, void **data) hashmap_return_entry (hashmap_t map, hashmap_iter iter, char **key,
void **data)
{ {
unsigned int i; unsigned int i;
struct hashentry_s *ptr; struct hashentry_s *ptr;
hashmap_iter count = 0; hashmap_iter count = 0;
assert(map != NULL); assert (map != NULL);
assert(iter >= 0); assert (iter >= 0);
assert(iter != map->end_iterator); assert (iter != map->end_iterator);
assert(key != NULL); assert (key != NULL);
assert(data != NULL); assert (data != NULL);
if (!map || iter < 0 || !key || !data) if (!map || iter < 0 || !key || !data)
return -EINVAL; return -EINVAL;
for (i = 0; i != map->size; i++) { for (i = 0; i != map->size; i++)
ptr = map->buckets[i].head; {
while (ptr) { ptr = map->buckets[i].head;
if (count == iter) { while (ptr)
/* This is the data so return it */ {
*key = ptr->key; if (count == iter)
*data = ptr->data; {
return ptr->len; /* This is the data so return it */
} *key = ptr->key;
*data = ptr->data;
return ptr->len;
}
ptr = ptr->next; ptr = ptr->next;
count++; count++;
} }
} }
return -EFAULT; return -EFAULT;
} }
/* /*
@ -379,31 +396,32 @@ hashmap_return_entry(hashmap_t map, hashmap_iter iter, char **key, void **data)
* count found * count found
*/ */
ssize_t ssize_t
hashmap_search(hashmap_t map, const char *key) hashmap_search (hashmap_t map, const char *key)
{ {
int hash; int hash;
struct hashentry_s *ptr; struct hashentry_s *ptr;
ssize_t count = 0; ssize_t count = 0;
if (map == NULL || key == NULL) if (map == NULL || key == NULL)
return -EINVAL; return -EINVAL;
hash = hashfunc(key, map->size); hash = hashfunc (key, map->size);
if (hash < 0) if (hash < 0)
return hash; return hash;
ptr = map->buckets[hash].head; ptr = map->buckets[hash].head;
/* All right, there is an entry here, now see if it's the one we want */ /* All right, there is an entry here, now see if it's the one we want */
while (ptr) { while (ptr)
if (strcasecmp(ptr->key, key) == 0) {
++count; if (strcasecmp (ptr->key, key) == 0)
++count;
/* This entry didn't contain the key; move to the next one */ /* This entry didn't contain the key; move to the next one */
ptr = ptr->next; ptr = ptr->next;
} }
return count; return count;
} }
/* /*
@ -415,30 +433,32 @@ hashmap_search(hashmap_t map, const char *key)
* length of data for the entry * length of data for the entry
*/ */
ssize_t ssize_t
hashmap_entry_by_key(hashmap_t map, const char *key, void **data) hashmap_entry_by_key (hashmap_t map, const char *key, void **data)
{ {
int hash; int hash;
struct hashentry_s *ptr; struct hashentry_s *ptr;
if (!map || !key || !data) if (!map || !key || !data)
return -EINVAL; return -EINVAL;
hash = hashfunc(key, map->size); hash = hashfunc (key, map->size);
if (hash < 0) if (hash < 0)
return hash; return hash;
ptr = map->buckets[hash].head; ptr = map->buckets[hash].head;
while (ptr) { while (ptr)
if (strcasecmp(ptr->key, key) == 0) { {
*data = ptr->data; if (strcasecmp (ptr->key, key) == 0)
return ptr->len; {
} *data = ptr->data;
return ptr->len;
}
ptr = ptr->next; ptr = ptr->next;
} }
return 0; return 0;
} }
/* /*
@ -450,53 +470,55 @@ hashmap_entry_by_key(hashmap_t map, const char *key, void **data)
* positive count of entries deleted * positive count of entries deleted
*/ */
ssize_t ssize_t
hashmap_remove(hashmap_t map, const char *key) hashmap_remove (hashmap_t map, const char *key)
{ {
int hash; int hash;
struct hashentry_s *ptr, *next; struct hashentry_s *ptr, *next;
short int deleted = 0; short int deleted = 0;
if (map == NULL || key == NULL) if (map == NULL || key == NULL)
return -EINVAL; return -EINVAL;
hash = hashfunc(key, map->size); hash = hashfunc (key, map->size);
if (hash < 0) if (hash < 0)
return hash; return hash;
ptr = map->buckets[hash].head; ptr = map->buckets[hash].head;
while (ptr) { while (ptr)
if (strcasecmp(ptr->key, key) == 0) { {
/* if (strcasecmp (ptr->key, key) == 0)
* Found the data, now need to remove everything {
* and update the hashmap. /*
*/ * Found the data, now need to remove everything
next = ptr->next; * and update the hashmap.
*/
next = ptr->next;
if (ptr->prev) if (ptr->prev)
ptr->prev->next = ptr->next; ptr->prev->next = ptr->next;
if (ptr->next) if (ptr->next)
ptr->next->prev = ptr->prev; ptr->next->prev = ptr->prev;
if (map->buckets[hash].head == ptr) if (map->buckets[hash].head == ptr)
map->buckets[hash].head = ptr->next; map->buckets[hash].head = ptr->next;
if (map->buckets[hash].tail == ptr) if (map->buckets[hash].tail == ptr)
map->buckets[hash].tail = ptr->prev; map->buckets[hash].tail = ptr->prev;
safefree(ptr->key); safefree (ptr->key);
safefree(ptr->data); safefree (ptr->data);
safefree(ptr); safefree (ptr);
++deleted; ++deleted;
--map->end_iterator; --map->end_iterator;
ptr = next; ptr = next;
continue; continue;
} }
/* This entry didn't contain the key; move to the next one */ /* This entry didn't contain the key; move to the next one */
ptr = ptr->next; ptr = ptr->next;
} }
/* The key was not found, so return 0 */ /* The key was not found, so return 0 */
return deleted; return deleted;
} }

View File

@ -23,7 +23,8 @@
/* Allow the use in C++ code. */ /* Allow the use in C++ code. */
#if defined(__cplusplus) #if defined(__cplusplus)
extern "C" { extern "C"
{
#endif #endif
/* /*
@ -31,15 +32,15 @@ extern "C" {
* hash map. Sure, it's a pointer, but the struct is hidden in the C file. * hash map. Sure, it's a pointer, but the struct is hidden in the C file.
* So, just use the hashmap_t like it's a cookie. :) * So, just use the hashmap_t like it's a cookie. :)
*/ */
typedef struct hashmap_s *hashmap_t; typedef struct hashmap_s *hashmap_t;
typedef int hashmap_iter; typedef int hashmap_iter;
/* /*
* hashmap_create() takes one argument, which is the number of buckets to * hashmap_create() takes one argument, which is the number of buckets to
* use internally. hashmap_delete() is self explanatory. * use internally. hashmap_delete() is self explanatory.
*/ */
extern hashmap_t hashmap_create(unsigned int nbuckets); extern hashmap_t hashmap_create (unsigned int nbuckets);
extern int hashmap_delete(hashmap_t map); extern int hashmap_delete (hashmap_t map);
/* /*
* When the you insert a key/data pair into the hashmap it will the key * When the you insert a key/data pair into the hashmap it will the key
@ -50,15 +51,15 @@ extern "C" {
* Returns: negative on error * Returns: negative on error
* 0 upon successful insert * 0 upon successful insert
*/ */
extern int hashmap_insert(hashmap_t map, const char *key, extern int hashmap_insert (hashmap_t map, const char *key,
const void *data, size_t len); const void *data, size_t len);
/* /*
* Get an iterator to the first entry. * Get an iterator to the first entry.
* *
* Returns: an negative value upon error. * Returns: an negative value upon error.
*/ */
extern hashmap_iter hashmap_first(hashmap_t map); extern hashmap_iter hashmap_first (hashmap_t map);
/* /*
* Checks to see if the iterator is pointing at the "end" of the entries. * Checks to see if the iterator is pointing at the "end" of the entries.
@ -66,7 +67,7 @@ extern "C" {
* Returns: 1 if it is the end * Returns: 1 if it is the end
* 0 otherwise * 0 otherwise
*/ */
extern int hashmap_is_end(hashmap_t map, hashmap_iter iter); extern int hashmap_is_end (hashmap_t map, hashmap_iter iter);
/* /*
* Return a "pointer" to the first instance of the particular key. It can * Return a "pointer" to the first instance of the particular key. It can
@ -76,7 +77,7 @@ extern "C" {
* an "iterator" pointing at the first key * an "iterator" pointing at the first key
* an "end-iterator" if the key wasn't found * an "end-iterator" if the key wasn't found
*/ */
extern hashmap_iter hashmap_find(hashmap_t map, const char *key); extern hashmap_iter hashmap_find (hashmap_t map, const char *key);
/* /*
* Retrieve the key/data associated with a particular iterator. * Retrieve the key/data associated with a particular iterator.
@ -86,8 +87,8 @@ extern "C" {
* Returns: the length of the data block upon success * Returns: the length of the data block upon success
* negative upon error * negative upon error
*/ */
extern ssize_t hashmap_return_entry(hashmap_t map, hashmap_iter iter, extern ssize_t hashmap_return_entry (hashmap_t map, hashmap_iter iter,
char **key, void **data); char **key, void **data);
/* /*
* Get the first entry (assuming there is more than one) for a particular * Get the first entry (assuming there is more than one) for a particular
@ -97,8 +98,8 @@ extern "C" {
* zero if no entry is found * zero if no entry is found
* length of data for the entry * length of data for the entry
*/ */
extern ssize_t hashmap_entry_by_key(hashmap_t map, const char *key, extern ssize_t hashmap_entry_by_key (hashmap_t map, const char *key,
void **data); void **data);
/* /*
* Searches for _any_ occurrances of "key" within the hashmap and returns the * Searches for _any_ occurrances of "key" within the hashmap and returns the
@ -108,7 +109,7 @@ extern "C" {
* zero if no key is found * zero if no key is found
* count found (positive value) * count found (positive value)
*/ */
extern ssize_t hashmap_search(hashmap_t map, const char *key); extern ssize_t hashmap_search (hashmap_t map, const char *key);
/* /*
* Go through the hashmap and remove the particular key. * Go through the hashmap and remove the particular key.
@ -118,9 +119,9 @@ extern "C" {
* 0 if the key was not found * 0 if the key was not found
* positive count of entries deleted * positive count of entries deleted
*/ */
extern ssize_t hashmap_remove(hashmap_t map, const char *key); extern ssize_t hashmap_remove (hashmap_t map, const char *key);
#if defined(__cplusplus) #if defined(__cplusplus)
} }
#endif /* C++ */ #endif /* C++ */
#endif /* _HASHMAP_H */ #endif /* _HASHMAP_H */

View File

@ -28,71 +28,72 @@
#include "text.h" #include "text.h"
void * void *
debugging_calloc(size_t nmemb, size_t size, const char *file, debugging_calloc (size_t nmemb, size_t size, const char *file,
unsigned long line) unsigned long line)
{ {
void *ptr; void *ptr;
assert(nmemb > 0); assert (nmemb > 0);
assert(size > 0); assert (size > 0);
ptr = calloc(nmemb, size); ptr = calloc (nmemb, size);
fprintf(stderr, "{calloc: %p:%zu x %zu} %s:%lu\n", ptr, nmemb, size, file, fprintf (stderr, "{calloc: %p:%zu x %zu} %s:%lu\n", ptr, nmemb, size, file,
line); line);
return ptr; return ptr;
} }
void * void *
debugging_malloc(size_t size, const char *file, unsigned long line) debugging_malloc (size_t size, const char *file, unsigned long line)
{ {
void *ptr; void *ptr;
assert(size > 0); assert (size > 0);
ptr = malloc(size); ptr = malloc (size);
fprintf(stderr, "{malloc: %p:%zu} %s:%lu\n", ptr, size, file, line); fprintf (stderr, "{malloc: %p:%zu} %s:%lu\n", ptr, size, file, line);
return ptr; return ptr;
} }
void * void *
debugging_realloc(void *ptr, size_t size, const char *file, unsigned long line) debugging_realloc (void *ptr, size_t size, const char *file,
unsigned long line)
{ {
void *newptr; void *newptr;
assert(size > 0); assert (size > 0);
newptr = realloc(ptr, size); newptr = realloc (ptr, size);
fprintf(stderr, "{realloc: %p -> %p:%zu} %s:%lu\n", ptr, newptr, size, fprintf (stderr, "{realloc: %p -> %p:%zu} %s:%lu\n", ptr, newptr, size,
file, line); file, line);
return newptr; return newptr;
} }
void void
debugging_free(void *ptr, const char *file, unsigned long line) debugging_free (void *ptr, const char *file, unsigned long line)
{ {
fprintf(stderr, "{free: %p} %s:%lu\n", ptr, file, line); fprintf (stderr, "{free: %p} %s:%lu\n", ptr, file, line);
if (ptr != NULL) if (ptr != NULL)
free(ptr); free (ptr);
return; return;
} }
char * char *
debugging_strdup(const char *s, const char *file, unsigned long line) debugging_strdup (const char *s, const char *file, unsigned long line)
{ {
char *ptr; char *ptr;
size_t len; size_t len;
assert(s != NULL); assert (s != NULL);
len = strlen(s) + 1; len = strlen (s) + 1;
ptr = malloc(len); ptr = malloc (len);
if (!ptr) if (!ptr)
return NULL; return NULL;
memcpy(ptr, s, len); memcpy (ptr, s, len);
fprintf(stderr, "{strdup: %p:%zu} %s:%lu\n", ptr, len, file, line); fprintf (stderr, "{strdup: %p:%zu} %s:%lu\n", ptr, len, file, line);
return ptr; return ptr;
} }
/* /*
@ -104,32 +105,32 @@ debugging_strdup(const char *s, const char *file, unsigned long line)
* solution. * solution.
*/ */
void * void *
malloc_shared_memory(size_t size) malloc_shared_memory (size_t size)
{ {
int fd; int fd;
void *ptr; void *ptr;
char buffer[32]; char buffer[32];
static char *shared_file = "/tmp/tinyproxy.shared.XXXXXX"; static char *shared_file = "/tmp/tinyproxy.shared.XXXXXX";
assert(size > 0); assert (size > 0);
strlcpy(buffer, shared_file, sizeof(buffer)); strlcpy (buffer, shared_file, sizeof (buffer));
/* 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.
*/ */
umask(0177); umask (0177);
if ((fd = mkstemp(buffer)) == -1) if ((fd = mkstemp (buffer)) == -1)
return MAP_FAILED; return MAP_FAILED;
unlink(buffer); unlink (buffer);
if (ftruncate(fd, size) == -1) if (ftruncate (fd, size) == -1)
return MAP_FAILED; return MAP_FAILED;
ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); ptr = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
return ptr; return ptr;
} }
/* /*
@ -137,21 +138,21 @@ malloc_shared_memory(size_t size)
* zero. * zero.
*/ */
void * void *
calloc_shared_memory(size_t nmemb, size_t size) calloc_shared_memory (size_t nmemb, size_t size)
{ {
void *ptr; void *ptr;
long length; long length;
assert(nmemb > 0); assert (nmemb > 0);
assert(size > 0); assert (size > 0);
length = nmemb * size; length = nmemb * size;
ptr = malloc_shared_memory(length); ptr = malloc_shared_memory (length);
if (ptr == MAP_FAILED) if (ptr == MAP_FAILED)
return ptr; return ptr;
memset(ptr, 0, length); memset (ptr, 0, length);
return ptr; return ptr;
} }

View File

@ -26,15 +26,15 @@
*/ */
#ifndef NDEBUG #ifndef NDEBUG
extern void *debugging_calloc(size_t nmemb, size_t size, const char *file, extern void *debugging_calloc (size_t nmemb, size_t size, const char *file,
unsigned long line); unsigned long line);
extern void *debugging_malloc(size_t size, const char *file, extern void *debugging_malloc (size_t size, const char *file,
unsigned long line); unsigned long line);
extern void debugging_free(void *ptr, const char *file, unsigned long line); extern void debugging_free (void *ptr, const char *file, unsigned long line);
extern void *debugging_realloc(void *ptr, size_t size, const char *file, extern void *debugging_realloc (void *ptr, size_t size, const char *file,
unsigned long line); unsigned long line);
extern char *debugging_strdup(const char *s, const char *file, extern char *debugging_strdup (const char *s, const char *file,
unsigned long line); unsigned long line);
# define safecalloc(x, y) debugging_calloc(x, y, __FILE__, __LINE__) # define safecalloc(x, y) debugging_calloc(x, y, __FILE__, __LINE__)
# define safemalloc(x) debugging_malloc(x, __FILE__, __LINE__) # define safemalloc(x) debugging_malloc(x, __FILE__, __LINE__)
@ -60,7 +60,7 @@ free(*__safefree_tmp); \
/* /*
* Allocate memory from the "shared" region of memory. * Allocate memory from the "shared" region of memory.
*/ */
extern void *malloc_shared_memory(size_t size); extern void *malloc_shared_memory (size_t size);
extern void *calloc_shared_memory(size_t nmemb, size_t size); extern void *calloc_shared_memory (size_t nmemb, size_t size);
#endif #endif

View File

@ -33,77 +33,77 @@
/* /*
* Add an error number -> filename mapping to the errorpages list. * Add an error number -> filename mapping to the errorpages list.
*/ */
#define ERRORNUM_BUFSIZE 8 /* this is more than required */ #define ERRORNUM_BUFSIZE 8 /* this is more than required */
#define ERRPAGES_BUCKETCOUNT 16 #define ERRPAGES_BUCKETCOUNT 16
int int
add_new_errorpage(char *filepath, unsigned int errornum) add_new_errorpage (char *filepath, unsigned int errornum)
{ {
char errornbuf[ERRORNUM_BUFSIZE]; char errornbuf[ERRORNUM_BUFSIZE];
config.errorpages = hashmap_create(ERRPAGES_BUCKETCOUNT); config.errorpages = hashmap_create (ERRPAGES_BUCKETCOUNT);
if (!config.errorpages) if (!config.errorpages)
return (-1); return (-1);
snprintf(errornbuf, ERRORNUM_BUFSIZE, "%u", errornum); snprintf (errornbuf, ERRORNUM_BUFSIZE, "%u", errornum);
if (hashmap_insert(config.errorpages, errornbuf, if (hashmap_insert (config.errorpages, errornbuf,
filepath, strlen(filepath) + 1) < 0) filepath, strlen (filepath) + 1) < 0)
return (-1); return (-1);
return (0); return (0);
} }
/* /*
* Get the file appropriate for a given error. * Get the file appropriate for a given error.
*/ */
static char * static char *
get_html_file(unsigned int errornum) get_html_file (unsigned int errornum)
{ {
hashmap_iter result_iter; hashmap_iter result_iter;
char errornbuf[ERRORNUM_BUFSIZE]; char errornbuf[ERRORNUM_BUFSIZE];
char *key; char *key;
static char *val; static char *val;
assert(errornum >= 100 && errornum < 1000); assert (errornum >= 100 && errornum < 1000);
if (!config.errorpages) if (!config.errorpages)
return (config.errorpage_undef); return (config.errorpage_undef);
snprintf(errornbuf, ERRORNUM_BUFSIZE, "%u", errornum); snprintf (errornbuf, ERRORNUM_BUFSIZE, "%u", errornum);
result_iter = hashmap_find(config.errorpages, errornbuf); result_iter = hashmap_find (config.errorpages, errornbuf);
if (hashmap_is_end(config.errorpages, result_iter)) if (hashmap_is_end (config.errorpages, result_iter))
return (config.errorpage_undef); return (config.errorpage_undef);
if (hashmap_return_entry(config.errorpages, result_iter, if (hashmap_return_entry (config.errorpages, result_iter,
&key, (void **)&val) < 0) &key, (void **) &val) < 0)
return (config.errorpage_undef); return (config.errorpage_undef);
return (val); return (val);
} }
/* /*
* Look up the value for a variable. * Look up the value for a variable.
*/ */
static char * static char *
lookup_variable(struct conn_s *connptr, char *varname) lookup_variable (struct conn_s *connptr, char *varname)
{ {
hashmap_iter result_iter; hashmap_iter result_iter;
char *key; char *key;
static char *data; static char *data;
result_iter = hashmap_find(connptr->error_variables, varname); result_iter = hashmap_find (connptr->error_variables, varname);
if (hashmap_is_end(connptr->error_variables, result_iter)) if (hashmap_is_end (connptr->error_variables, result_iter))
return (NULL); return (NULL);
if (hashmap_return_entry(connptr->error_variables, result_iter, if (hashmap_return_entry (connptr->error_variables, result_iter,
&key, (void **)&data) < 0) &key, (void **) &data) < 0)
return (NULL); return (NULL);
return (data); return (data);
} }
#define HTML_BUFSIZE 4096 #define HTML_BUFSIZE 4096
@ -112,116 +112,113 @@ lookup_variable(struct conn_s *connptr, char *varname)
* Send an already-opened file to the client with variable substitution. * Send an already-opened file to the client with variable substitution.
*/ */
int int
send_html_file(FILE * infile, struct conn_s *connptr) send_html_file (FILE * infile, struct conn_s *connptr)
{ {
char inbuf[HTML_BUFSIZE], *varstart = NULL, *p; char inbuf[HTML_BUFSIZE], *varstart = NULL, *p;
char *varval; char *varval;
int in_variable = 0, writeret; int in_variable = 0, writeret;
while (fgets(inbuf, HTML_BUFSIZE, infile) != NULL) { while (fgets (inbuf, HTML_BUFSIZE, infile) != NULL)
for (p = inbuf; *p; p++) { {
switch (*p) { for (p = inbuf; *p; p++)
case '}': {
if (in_variable) { switch (*p)
*p = '\0'; {
if (! case '}':
(varval = if (in_variable)
lookup_variable(connptr, {
varstart))) *p = '\0';
varval = "(unknown)"; if (!(varval = lookup_variable (connptr, varstart)))
writeret = varval = "(unknown)";
write_message(connptr->client_fd, writeret = write_message (connptr->client_fd, "%s", varval);
"%s", varval); if (writeret)
if (writeret) return (writeret);
return (writeret); in_variable = 0;
in_variable = 0; }
} else { else
writeret = {
write_message(connptr->client_fd, writeret = write_message (connptr->client_fd, "%c", *p);
"%c", *p); if (writeret)
if (writeret) return (writeret);
return (writeret); }
} break;
break; case '{':
case '{': /* a {{ will print a single {. If we are NOT
/* a {{ will print a single {. If we are NOT * already in a { variable, then proceed with
* already in a { variable, then proceed with * setup. If we ARE already in a { variable,
* setup. If we ARE already in a { variable, * this code will fallthrough to the code that
* this code will fallthrough to the code that * just dumps a character to the client fd.
* just dumps a character to the client fd. */
*/ if (!in_variable)
if (!in_variable) { {
varstart = p + 1; varstart = p + 1;
in_variable++; in_variable++;
} else }
in_variable = 0; else
default: in_variable = 0;
if (!in_variable) { default:
writeret = if (!in_variable)
write_message(connptr->client_fd, {
"%c", *p); writeret = write_message (connptr->client_fd, "%c", *p);
if (writeret) if (writeret)
return (writeret); return (writeret);
} }
} }
} }
in_variable = 0; in_variable = 0;
} }
return (0); return (0);
} }
int int
send_http_headers(struct conn_s *connptr, int code, char *message) send_http_headers (struct conn_s *connptr, int code, char *message)
{ {
char *headers = 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" "Connection: close\r\n" "\r\n"; "Content-Type: text/html\r\n" "Connection: close\r\n" "\r\n";
return (write_message(connptr->client_fd, headers, return (write_message (connptr->client_fd, headers,
code, message, PACKAGE, VERSION)); code, message, PACKAGE, VERSION));
} }
/* /*
* Display an error to the client. * Display an error to the client.
*/ */
int int
send_http_error_message(struct conn_s *connptr) send_http_error_message (struct conn_s *connptr)
{ {
char *error_file; char *error_file;
FILE *infile; FILE *infile;
int ret; int ret;
char *fallback_error = char *fallback_error =
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
"<html>\n" "<html>\n"
"<head><title>%d %s</title></head>\n" "<head><title>%d %s</title></head>\n"
"<body>\n" "<body>\n"
"<h1>%s</h1>\n" "<h1>%s</h1>\n"
"<p>%s</p>\n" "<p>%s</p>\n"
"<hr />\n" "<hr />\n"
"<p><em>Generated by %s version %s.</em></p>\n" "<p><em>Generated by %s version %s.</em></p>\n" "</body>\n" "</html>\n";
"</body>\n"
"</html>\n";
send_http_headers(connptr, connptr->error_number, send_http_headers (connptr, connptr->error_number, connptr->error_string);
connptr->error_string);
error_file = get_html_file(connptr->error_number); error_file = get_html_file (connptr->error_number);
if (!(infile = fopen(error_file, "r"))) { if (!(infile = fopen (error_file, "r")))
char *detail = lookup_variable(connptr, "detail"); {
return (write_message(connptr->client_fd, fallback_error, char *detail = lookup_variable (connptr, "detail");
connptr->error_number, return (write_message (connptr->client_fd, fallback_error,
connptr->error_string, connptr->error_number,
connptr->error_string, connptr->error_string,
detail, connptr->error_string,
PACKAGE, VERSION)); detail, PACKAGE, VERSION));
} }
ret = send_html_file(infile, connptr); ret = send_html_file (infile, connptr);
fclose(infile); fclose (infile);
return (ret); return (ret);
} }
/* /*
@ -231,16 +228,14 @@ send_http_error_message(struct conn_s *connptr)
#define ERRVAR_BUCKETCOUNT 16 #define ERRVAR_BUCKETCOUNT 16
int int
add_error_variable(struct conn_s *connptr, char *key, char *val) add_error_variable (struct conn_s *connptr, char *key, char *val)
{ {
if (!connptr->error_variables) if (!connptr->error_variables)
if (! if (!(connptr->error_variables = hashmap_create (ERRVAR_BUCKETCOUNT)))
(connptr->error_variables = return (-1);
hashmap_create(ERRVAR_BUCKETCOUNT)))
return (-1);
return hashmap_insert(connptr->error_variables, key, val, return hashmap_insert (connptr->error_variables, key, val,
strlen(val) + 1); strlen (val) + 1);
} }
#define ADD_VAR_RET(x, y) \ #define ADD_VAR_RET(x, y) \
@ -255,61 +250,63 @@ add_error_variable(struct conn_s *connptr, char *key, char *val)
* Set some standard variables used by all HTML pages * Set some standard variables used by all HTML pages
*/ */
int int
add_standard_vars(struct conn_s *connptr) add_standard_vars (struct conn_s *connptr)
{ {
char errnobuf[16]; char errnobuf[16];
char timebuf[30]; char timebuf[30];
time_t global_time; time_t global_time;
snprintf(errnobuf, sizeof errnobuf, "%d", connptr->error_number); snprintf (errnobuf, sizeof errnobuf, "%d", connptr->error_number);
ADD_VAR_RET("errno", errnobuf); ADD_VAR_RET ("errno", errnobuf);
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); 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
* add_error_variable() directly. * add_error_variable() directly.
*/ */
global_time = time(NULL); global_time = time (NULL);
strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", strftime (timebuf, sizeof (timebuf), "%a, %d %b %Y %H:%M:%S GMT",
gmtime(&global_time)); gmtime (&global_time));
add_error_variable(connptr, "date", timebuf); add_error_variable (connptr, "date", timebuf);
add_error_variable(connptr, "website", "http://tinyproxy.banu.com/"); add_error_variable (connptr, "website", "http://tinyproxy.banu.com/");
add_error_variable(connptr, "version", VERSION); add_error_variable (connptr, "version", VERSION);
add_error_variable(connptr, "package", PACKAGE); add_error_variable (connptr, "package", PACKAGE);
return (0); return (0);
} }
/* /*
* Add the error information to the conn structure. * Add the error information to the conn structure.
*/ */
int int
indicate_http_error(struct conn_s *connptr, int number, char *message, ...) indicate_http_error (struct conn_s *connptr, int number, char *message, ...)
{ {
va_list ap; va_list ap;
char *key, *val; char *key, *val;
va_start(ap, message); va_start (ap, message);
while ((key = va_arg(ap, char *))) { while ((key = va_arg (ap, char *)))
val = va_arg(ap, char *); {
val = va_arg (ap, char *);
if (add_error_variable(connptr, key, val) == -1) { if (add_error_variable (connptr, key, val) == -1)
va_end(ap); {
return (-1); va_end (ap);
} return (-1);
} }
}
connptr->error_number = number; connptr->error_number = number;
connptr->error_string = safestrdup(message); connptr->error_string = safestrdup (message);
va_end(ap); va_end (ap);
return (add_standard_vars(connptr)); return (add_standard_vars (connptr));
} }

View File

@ -24,13 +24,14 @@
/* Forward declaration */ /* Forward declaration */
struct conn_s; struct conn_s;
extern int add_new_errorpage(char *filepath, unsigned int errornum); extern int add_new_errorpage (char *filepath, unsigned int errornum);
extern int send_http_error_message(struct conn_s *connptr); extern int send_http_error_message (struct conn_s *connptr);
extern int indicate_http_error(struct conn_s *connptr, int number, extern int indicate_http_error (struct conn_s *connptr, int number,
char *message, ...); char *message, ...);
extern int add_error_variable(struct conn_s *connptr, char *key, char *val); extern int add_error_variable (struct conn_s *connptr, char *key, char *val);
extern int send_html_file(FILE * infile, struct conn_s *connptr); extern int send_html_file (FILE * infile, struct conn_s *connptr);
extern int send_http_headers(struct conn_s *connptr, int code, char *message); extern int send_http_headers (struct conn_s *connptr, int code,
extern int add_standard_vars(struct conn_s *connptr); char *message);
extern int add_standard_vars (struct conn_s *connptr);
#endif /* !TINYPROXY_HTML_ERROR_H */ #endif /* !TINYPROXY_HTML_ERROR_H */

View File

@ -30,29 +30,33 @@
* Also, the caller MUST NOT free the memory while the structure is * Also, the caller MUST NOT free the memory while the structure is
* still in use---bad things would happen. * still in use---bad things would happen.
*/ */
struct http_message_s { struct http_message_s
/* Response string and code supplied on the HTTP status line */ {
struct { /* Response string and code supplied on the HTTP status line */
const char *string; struct
int code; {
} response; const char *string;
int code;
} response;
/* /*
* A group of headers to be sent with this message. Right now * A group of headers to be sent with this message. Right now
* the strings are referenced through pointers in an array. * the strings are referenced through pointers in an array.
* I might change this to a vector in the future. * I might change this to a vector in the future.
*/ */
struct { struct
char **strings; {
unsigned int total; char **strings;
unsigned int used; unsigned int total;
} headers; unsigned int used;
} headers;
/* Body of the message (most likely an HTML message) */ /* Body of the message (most likely an HTML message) */
struct { struct
const char *text; {
size_t length; const char *text;
} body; size_t length;
} body;
}; };
/* /*
@ -61,18 +65,18 @@ struct http_message_s {
* number is returned. Useful for if() tests and assert() tests. * number is returned. Useful for if() tests and assert() tests.
*/ */
static int static int
is_http_message_valid(http_message_t msg) is_http_message_valid (http_message_t msg)
{ {
if (msg == NULL) if (msg == NULL)
return 0; return 0;
if (msg->headers.strings == NULL) if (msg->headers.strings == NULL)
return 0; return 0;
if (msg->response.string == NULL) if (msg->response.string == NULL)
return 0; return 0;
if (msg->response.code < 1 || msg->response.code > 999) if (msg->response.code < 1 || msg->response.code > 999)
return 0; return 0;
return 1; return 1;
} }
/* Initially allocate space for 128 headers */ /* Initially allocate space for 128 headers */
@ -83,32 +87,34 @@ is_http_message_valid(http_message_t msg)
* If memory could not be allocated, return a NULL. * If memory could not be allocated, return a NULL.
*/ */
http_message_t http_message_t
http_message_create(int response_code, const char *response_string) http_message_create (int response_code, const char *response_string)
{ {
http_message_t msg; http_message_t msg;
int ret; int ret;
msg = safecalloc(1, sizeof(struct http_message_s)); msg = safecalloc (1, sizeof (struct http_message_s));
if (msg == NULL) if (msg == NULL)
return NULL; return NULL;
msg->headers.strings = safecalloc(NUMBER_OF_HEADERS, sizeof(char *)); msg->headers.strings = safecalloc (NUMBER_OF_HEADERS, sizeof (char *));
if (msg->headers.strings == NULL) { if (msg->headers.strings == NULL)
safefree(msg); {
return NULL; safefree (msg);
} return NULL;
}
msg->headers.total = NUMBER_OF_HEADERS; msg->headers.total = NUMBER_OF_HEADERS;
/* Store the HTTP response information in the structure */ /* Store the HTTP response information in the structure */
ret = http_message_set_response(msg, response_code, response_string); ret = http_message_set_response (msg, response_code, response_string);
if (IS_HTTP_MSG_ERROR(ret)) { if (IS_HTTP_MSG_ERROR (ret))
safefree(msg->headers.strings); {
safefree(msg); safefree (msg->headers.strings);
return NULL; safefree (msg);
} return NULL;
}
return msg; return msg;
} }
/* /*
@ -117,19 +123,19 @@ http_message_create(int response_code, const char *response_string)
* is the responsibility of the caller. * is the responsibility of the caller.
*/ */
int int
http_message_destroy(http_message_t msg) http_message_destroy (http_message_t msg)
{ {
assert(msg != NULL); assert (msg != NULL);
assert(msg->headers.strings != NULL); assert (msg->headers.strings != NULL);
/* Check for valid arguments */ /* Check for valid arguments */
if (msg == NULL) if (msg == NULL)
return -EFAULT; return -EFAULT;
if (msg->headers.strings != NULL) if (msg->headers.strings != NULL)
safefree(msg->headers.strings); safefree (msg->headers.strings);
safefree(msg); safefree (msg);
return 0; return 0;
} }
/* /*
@ -137,135 +143,135 @@ http_message_destroy(http_message_t msg)
* must be a NUL ('\0') terminated C string. * must be a NUL ('\0') terminated C string.
*/ */
int int
http_message_set_response(http_message_t msg, http_message_set_response (http_message_t msg,
int response_code, const char *response_string) int response_code, const char *response_string)
{ {
/* Check for valid arguments */ /* Check for valid arguments */
if (msg == NULL) if (msg == NULL)
return -EFAULT; return -EFAULT;
if (response_code < 1 || response_code > 999) if (response_code < 1 || response_code > 999)
return -EINVAL; return -EINVAL;
if (response_string == NULL) if (response_string == NULL)
return -EINVAL; return -EINVAL;
if (strlen(response_string) == 0) if (strlen (response_string) == 0)
return -EINVAL; return -EINVAL;
msg->response.code = response_code; msg->response.code = response_code;
msg->response.string = response_string; msg->response.string = response_string;
return 0; return 0;
} }
/* /*
* Set the HTTP message body. * Set the HTTP message body.
*/ */
int int
http_message_set_body(http_message_t msg, const char *body, size_t len) http_message_set_body (http_message_t msg, const char *body, size_t len)
{ {
/* Check for valid arguments */ /* Check for valid arguments */
if (msg == NULL) if (msg == NULL)
return -EFAULT; return -EFAULT;
if (body == NULL) if (body == NULL)
return -EINVAL; return -EINVAL;
if (len == 0) if (len == 0)
return -EINVAL; return -EINVAL;
msg->body.text = body; msg->body.text = body;
msg->body.length = len; msg->body.length = len;
return 0; return 0;
} }
/* /*
* Add headers to the structure. * Add headers to the structure.
*/ */
int int
http_message_add_headers(http_message_t msg, char **headers, int num_headers) http_message_add_headers (http_message_t msg, char **headers, int num_headers)
{ {
char **new_headers; char **new_headers;
int i; int i;
/* Check for valid arguments */ /* Check for valid arguments */
if (msg == NULL) if (msg == NULL)
return -EFAULT; return -EFAULT;
if (headers == NULL) if (headers == NULL)
return -EINVAL; return -EINVAL;
if (num_headers < 1) if (num_headers < 1)
return -EINVAL; return -EINVAL;
/* /*
* If the number of headers to add is greater than the space * If the number of headers to add is greater than the space
* available, reallocate the memory. * available, reallocate the memory.
*/ */
if (msg->headers.used + num_headers > msg->headers.total) { if (msg->headers.used + num_headers > msg->headers.total)
new_headers = safecalloc(msg->headers.total * 2, {
sizeof(char *)); new_headers = safecalloc (msg->headers.total * 2, sizeof (char *));
if (new_headers == NULL) if (new_headers == NULL)
return -ENOMEM; return -ENOMEM;
/* Copy the array */ /* Copy the array */
for (i = 0; i != msg->headers.used; ++i) for (i = 0; i != msg->headers.used; ++i)
new_headers[i] = msg->headers.strings[i]; new_headers[i] = msg->headers.strings[i];
/* Remove the old array and replace it with the new array */ /* Remove the old array and replace it with the new array */
safefree(msg->headers.strings); safefree (msg->headers.strings);
msg->headers.strings = new_headers; msg->headers.strings = new_headers;
msg->headers.total *= 2; msg->headers.total *= 2;
} }
/* /*
* Add the new headers to the structure * Add the new headers to the structure
*/ */
for (i = 0; i != num_headers; ++i) for (i = 0; i != num_headers; ++i)
msg->headers.strings[i + msg->headers.used] = headers[i]; msg->headers.strings[i + msg->headers.used] = headers[i];
msg->headers.used += num_headers; msg->headers.used += num_headers;
return 0; return 0;
} }
/* /*
* Send the completed HTTP message via the supplied file descriptor. * Send the completed HTTP message via the supplied file descriptor.
*/ */
int int
http_message_send(http_message_t msg, int fd) http_message_send (http_message_t msg, int fd)
{ {
char timebuf[30]; char timebuf[30];
time_t global_time; time_t global_time;
unsigned int i; unsigned int i;
assert(is_http_message_valid(msg)); assert (is_http_message_valid (msg));
/* Check for valid arguments */ /* Check for valid arguments */
if (msg == NULL) if (msg == NULL)
return -EFAULT; return -EFAULT;
if (fd < 1) if (fd < 1)
return -EBADF; return -EBADF;
if (!is_http_message_valid(msg)) if (!is_http_message_valid (msg))
return -EINVAL; return -EINVAL;
/* Write the response line */ /* Write the response line */
write_message(fd, "HTTP/1.0 %d %s\r\n", write_message (fd, "HTTP/1.0 %d %s\r\n",
msg->response.code, msg->response.string); msg->response.code, msg->response.string);
/* Go through all the headers */ /* Go through all the headers */
for (i = 0; i != msg->headers.used; ++i) for (i = 0; i != msg->headers.used; ++i)
write_message(fd, "%s\r\n", msg->headers.strings[i]); write_message (fd, "%s\r\n", msg->headers.strings[i]);
/* Output the date */ /* Output the date */
global_time = time(NULL); global_time = time (NULL);
strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", strftime (timebuf, sizeof (timebuf), "%a, %d %b %Y %H:%M:%S GMT",
gmtime(&global_time)); gmtime (&global_time));
write_message(fd, "Date: %s\r\n", timebuf); write_message (fd, "Date: %s\r\n", timebuf);
/* Output the content-length */ /* Output the content-length */
write_message(fd, "Content-length: %u\r\n", msg->body.length); write_message (fd, "Content-length: %u\r\n", msg->body.length);
/* Write the separator between the headers and body */ /* Write the separator between the headers and body */
safe_write(fd, "\r\n", 2); safe_write (fd, "\r\n", 2);
/* If there's a body, send it! */ /* If there's a body, send it! */
if (msg->body.length > 0) if (msg->body.length > 0)
safe_write(fd, msg->body.text, msg->body.length); safe_write (fd, msg->body.text, msg->body.length);
return 0; return 0;
} }

View File

@ -58,28 +58,28 @@ typedef struct http_message_s *http_message_t;
#define IS_HTTP_MSG_ERROR(x) (x < 0) #define IS_HTTP_MSG_ERROR(x) (x < 0)
/* Initialize the internal structure of the HTTP message */ /* Initialize the internal structure of the HTTP message */
extern http_message_t http_message_create(int response_code, extern http_message_t http_message_create (int response_code,
const char *response_string); const char *response_string);
/* Free up an _internal_ resources */ /* Free up an _internal_ resources */
extern int http_message_destroy(http_message_t msg); extern int http_message_destroy (http_message_t msg);
/* /*
* Send an HTTP message via the supplied file descriptor. This function * Send an HTTP message via the supplied file descriptor. This function
* will add the "Date" header before it's sent. * will add the "Date" header before it's sent.
*/ */
extern int http_message_send(http_message_t msg, int fd); extern int http_message_send (http_message_t msg, int fd);
/* /*
* Change the internal state of the HTTP message. Either set the * Change the internal state of the HTTP message. Either set the
* body of the message, update the response information, or * body of the message, update the response information, or
* add a new set of headers. * add a new set of headers.
*/ */
extern int http_message_set_body(http_message_t msg, extern int http_message_set_body (http_message_t msg,
const char *body, size_t len); const char *body, size_t len);
extern int http_message_set_response(http_message_t msg, extern int http_message_set_response (http_message_t msg,
int response_code, int response_code,
const char *response_string); const char *response_string);
/* /*
* Set the headers for this HTTP message. Each string must be NUL ('\0') * Set the headers for this HTTP message. Each string must be NUL ('\0')
@ -87,7 +87,7 @@ extern int http_message_set_response(http_message_t msg,
* line-feeds (LF) since they will be included when the http_message is * line-feeds (LF) since they will be included when the http_message is
* sent. * sent.
*/ */
extern int http_message_add_headers(http_message_t msg, extern int http_message_add_headers (http_message_t msg,
char **headers, int num_headers); char **headers, int num_headers);
#endif /* _TINYPROXY_HTTP_MESSAGE_H_ */ #endif /* _TINYPROXY_HTTP_MESSAGE_H_ */

210
src/log.c
View File

@ -29,15 +29,15 @@
#include "vector.h" #include "vector.h"
static char *syslog_level[] = { static char *syslog_level[] = {
NULL, NULL,
NULL, NULL,
"CRITICAL", "CRITICAL",
"ERROR", "ERROR",
"WARNING", "WARNING",
"NOTICE", "NOTICE",
"INFO", "INFO",
"DEBUG", "DEBUG",
"CONNECT" "CONNECT"
}; };
#define TIME_LENGTH 16 #define TIME_LENGTH 16
@ -65,165 +65,177 @@ static vector_t log_message_storage;
* 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.
*/ */
int int
open_log_file(const char *log_file_name) open_log_file (const char *log_file_name)
{ {
log_file_fd = create_file_safely(log_file_name, FALSE); log_file_fd = create_file_safely (log_file_name, FALSE);
return log_file_fd; return log_file_fd;
} }
/* /*
* Close the log file * Close the log file
*/ */
void void
close_log_file(void) close_log_file (void)
{ {
close(log_file_fd); close (log_file_fd);
} }
/* /*
* Truncate log file to a zero length. * Truncate log file to a zero length.
*/ */
void void
truncate_log_file(void) truncate_log_file (void)
{ {
lseek(log_file_fd, 0, SEEK_SET); lseek (log_file_fd, 0, SEEK_SET);
ftruncate(log_file_fd, 0); ftruncate (log_file_fd, 0);
} }
/* /*
* Set the log level for writing to the log file. * Set the log level for writing to the log file.
*/ */
void void
set_log_level(int level) set_log_level (int level)
{ {
log_level = level; log_level = level;
} }
/* /*
* This routine logs messages to either the log file or the syslog function. * This routine logs messages to either the log file or the syslog function.
*/ */
void void
log_message(int level, char *fmt, ...) log_message (int level, char *fmt, ...)
{ {
va_list args; va_list args;
time_t nowtime; time_t nowtime;
char time_string[TIME_LENGTH]; char time_string[TIME_LENGTH];
char str[STRING_LENGTH]; char str[STRING_LENGTH];
#ifdef NDEBUG #ifdef NDEBUG
/* /*
* Figure out if we should write the message or not. * Figure out if we should write the message or not.
*/ */
if (log_level == LOG_CONN) { if (log_level == LOG_CONN)
if (level == LOG_INFO) {
return; if (level == LOG_INFO)
} else if (log_level == LOG_INFO) { return;
if (level > LOG_INFO && level != LOG_CONN) }
return; else if (log_level == LOG_INFO)
} else if (level > log_level) {
return; if (level > LOG_INFO && level != LOG_CONN)
return;
}
else if (level > log_level)
return;
#endif #endif
#ifdef HAVE_SYSLOG_H #ifdef HAVE_SYSLOG_H
if (config.syslog && level == LOG_CONN) if (config.syslog && level == LOG_CONN)
level = LOG_INFO; level = LOG_INFO;
#endif #endif
va_start(args, fmt); va_start (args, fmt);
/* /*
* If the config file hasn't been processed, then we need to store * If the config file hasn't been processed, then we need to store
* the messages for later processing. * the messages for later processing.
*/ */
if (!processed_config_file) { if (!processed_config_file)
char *entry_buffer; {
char *entry_buffer;
if (!log_message_storage) { if (!log_message_storage)
log_message_storage = vector_create(); {
if (!log_message_storage) log_message_storage = vector_create ();
goto out; if (!log_message_storage)
} goto out;
}
vsnprintf(str, STRING_LENGTH, fmt, args); vsnprintf (str, STRING_LENGTH, fmt, args);
entry_buffer = safemalloc(strlen(str) + 6); entry_buffer = safemalloc (strlen (str) + 6);
if (!entry_buffer) if (!entry_buffer)
goto out; goto out;
sprintf(entry_buffer, "%d %s", level, str); sprintf (entry_buffer, "%d %s", level, str);
vector_append(log_message_storage, entry_buffer, vector_append (log_message_storage, entry_buffer,
strlen(entry_buffer) + 1); strlen (entry_buffer) + 1);
safefree(entry_buffer); safefree (entry_buffer);
goto out; goto out;
} }
#ifdef HAVE_SYSLOG_H #ifdef HAVE_SYSLOG_H
if (config.syslog) { if (config.syslog)
{
# 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
} else { }
else
{
#endif #endif
nowtime = time(NULL); nowtime = time (NULL);
/* Format is month day hour:minute:second (24 time) */ /* Format is month day hour:minute:second (24 time) */
strftime(time_string, TIME_LENGTH, "%b %d %H:%M:%S", strftime (time_string, TIME_LENGTH, "%b %d %H:%M:%S",
localtime(&nowtime)); localtime (&nowtime));
snprintf(str, STRING_LENGTH, "%-9s %s [%ld]: ", snprintf (str, STRING_LENGTH, "%-9s %s [%ld]: ",
syslog_level[level], time_string, (long int)getpid()); syslog_level[level], time_string, (long int) getpid ());
assert(log_file_fd >= 0); assert (log_file_fd >= 0);
write(log_file_fd, str, strlen(str)); write (log_file_fd, str, strlen (str));
vsnprintf(str, STRING_LENGTH, fmt, args); vsnprintf (str, STRING_LENGTH, fmt, args);
write(log_file_fd, str, strlen(str)); write (log_file_fd, str, strlen (str));
write(log_file_fd, "\n", 1); write (log_file_fd, "\n", 1);
fsync(log_file_fd); fsync (log_file_fd);
#ifdef HAVE_SYSLOG_H #ifdef HAVE_SYSLOG_H
} }
#endif #endif
out: out:
va_end(args); va_end (args);
} }
/* /*
* This needs to send any stored log messages. * This needs to send any stored log messages.
*/ */
void void
send_stored_logs(void) send_stored_logs (void)
{ {
char *string; char *string;
char *ptr; char *ptr;
int level; int level;
size_t i; size_t i;
for (i = 0; i != vector_length(log_message_storage); ++i) { for (i = 0; i != vector_length (log_message_storage); ++i)
string = vector_getentry(log_message_storage, i, NULL); {
string = vector_getentry (log_message_storage, i, NULL);
ptr = strchr(string, ' ') + 1; ptr = strchr (string, ' ') + 1;
level = atoi(string); level = atoi (string);
#ifdef NDEBUG #ifdef NDEBUG
if (log_level == LOG_CONN && level == LOG_INFO) if (log_level == LOG_CONN && level == LOG_INFO)
continue; continue;
else if (log_level == LOG_INFO) { else if (log_level == LOG_INFO)
if (level > LOG_INFO && level != LOG_CONN) {
continue; if (level > LOG_INFO && level != LOG_CONN)
} else if (level > log_level) continue;
continue; }
else if (level > log_level)
continue;
#endif #endif
log_message(level, ptr); log_message (level, ptr);
} }
vector_delete(log_message_storage); vector_delete (log_message_storage);
log_message_storage = NULL; log_message_storage = NULL;
} }

View File

@ -87,7 +87,7 @@
# define LOG_DEBUG 7 # define LOG_DEBUG 7
#endif #endif
#define LOG_CONN 8 /* extra to log connections without the INFO stuff */ #define LOG_CONN 8 /* extra to log connections without the INFO stuff */
/* /*
* Use this for debugging. The format is specific: * Use this for debugging. The format is specific:
@ -102,12 +102,12 @@
# define DEBUG2(x, y...) do { } while(0) # define DEBUG2(x, y...) do { } while(0)
#endif #endif
extern int open_log_file(const char *file); extern int open_log_file (const char *file);
extern void close_log_file(void); extern void close_log_file (void);
extern void truncate_log_file(void); extern void truncate_log_file (void);
extern void log_message(int level, char *fmt, ...); extern void log_message (int level, char *fmt, ...);
extern void set_log_level(int level); extern void set_log_level (int level);
extern void send_stored_logs(void); extern void send_stored_logs (void);
#endif #endif

View File

@ -33,35 +33,37 @@
* again. Keep sending until the buffer has been sent. * again. Keep sending until the buffer has been sent.
*/ */
ssize_t ssize_t
safe_write(int fd, const char *buffer, size_t count) safe_write (int fd, const char *buffer, size_t count)
{ {
ssize_t len; ssize_t len;
size_t bytestosend; size_t bytestosend;
assert(fd >= 0); assert (fd >= 0);
assert(buffer != NULL); assert (buffer != NULL);
assert(count > 0); assert (count > 0);
bytestosend = count; bytestosend = count;
while (1) { while (1)
len = send(fd, buffer, bytestosend, MSG_NOSIGNAL); {
len = send (fd, buffer, bytestosend, MSG_NOSIGNAL);
if (len < 0) { if (len < 0)
if (errno == EINTR) {
continue; if (errno == EINTR)
else continue;
return -errno; else
} return -errno;
}
if (len == bytestosend) if (len == bytestosend)
break; break;
buffer += len; buffer += len;
bytestosend -= len; bytestosend -= len;
} }
return count; return count;
} }
/* /*
@ -69,15 +71,17 @@ safe_write(int fd, const char *buffer, size_t count)
* again. * again.
*/ */
ssize_t ssize_t
safe_read(int fd, char *buffer, size_t count) safe_read (int fd, char *buffer, size_t count)
{ {
ssize_t len; ssize_t len;
do { do
len = read(fd, buffer, count); {
} while (len < 0 && errno == EINTR); len = read (fd, buffer, count);
}
while (len < 0 && errno == EINTR);
return len; return len;
} }
/* /*
@ -87,47 +91,51 @@ safe_read(int fd, char *buffer, size_t count)
* (although I did fix a memory leak. :) * (although I did fix a memory leak. :)
*/ */
int int
write_message(int fd, const char *fmt, ...) write_message (int fd, const char *fmt, ...)
{ {
ssize_t n; ssize_t n;
size_t size = (1024 * 8); /* start with 8 KB and go from there */ size_t size = (1024 * 8); /* start with 8 KB and go from there */
char *buf, *tmpbuf; char *buf, *tmpbuf;
va_list ap; va_list ap;
if ((buf = safemalloc(size)) == NULL) if ((buf = safemalloc (size)) == NULL)
return -1; return -1;
while (1) { while (1)
va_start(ap, fmt); {
n = vsnprintf(buf, size, fmt, ap); va_start (ap, fmt);
va_end(ap); n = vsnprintf (buf, size, fmt, ap);
va_end (ap);
/* If that worked, break out so we can send the buffer */ /* If that worked, break out so we can send the buffer */
if (n > -1 && n < size) if (n > -1 && n < size)
break; break;
/* Else, try again with more space */ /* Else, try again with more space */
if (n > -1) if (n > -1)
/* precisely what is needed (glibc2.1) */ /* precisely what is needed (glibc2.1) */
size = n + 1; size = n + 1;
else else
/* twice the old size (glibc2.0) */ /* twice the old size (glibc2.0) */
size *= 2; size *= 2;
if ((tmpbuf = saferealloc(buf, size)) == NULL) { if ((tmpbuf = saferealloc (buf, size)) == NULL)
safefree(buf); {
return -1; safefree (buf);
} else return -1;
buf = tmpbuf; }
} else
buf = tmpbuf;
}
if (safe_write(fd, buf, n) < 0) { if (safe_write (fd, buf, n) < 0)
safefree(buf); {
return -1; safefree (buf);
} return -1;
}
safefree(buf); safefree (buf);
return 0; return 0;
} }
/* /*
@ -142,103 +150,113 @@ write_message(int fd, const char *fmt, ...)
#define SEGMENT_LEN (512) #define SEGMENT_LEN (512)
#define MAXIMUM_BUFFER_LENGTH (128 * 1024) #define MAXIMUM_BUFFER_LENGTH (128 * 1024)
ssize_t ssize_t
readline(int fd, char **whole_buffer) readline (int fd, char **whole_buffer)
{ {
ssize_t whole_buffer_len; ssize_t whole_buffer_len;
char buffer[SEGMENT_LEN]; char buffer[SEGMENT_LEN];
char *ptr; char *ptr;
ssize_t ret; ssize_t ret;
ssize_t diff; ssize_t diff;
struct read_lines_s { struct read_lines_s
char *data; {
size_t len; char *data;
struct read_lines_s *next; size_t len;
}; struct read_lines_s *next;
struct read_lines_s *first_line, *line_ptr; };
struct read_lines_s *first_line, *line_ptr;
first_line = safecalloc(sizeof(struct read_lines_s), 1); first_line = safecalloc (sizeof (struct read_lines_s), 1);
if (!first_line) if (!first_line)
return -ENOMEM; return -ENOMEM;
line_ptr = first_line; line_ptr = first_line;
whole_buffer_len = 0; whole_buffer_len = 0;
for (;;) { for (;;)
ret = recv(fd, buffer, SEGMENT_LEN, MSG_PEEK); {
if (ret <= 0) ret = recv (fd, buffer, SEGMENT_LEN, MSG_PEEK);
goto CLEANUP; if (ret <= 0)
goto CLEANUP;
ptr = memchr(buffer, '\n', ret); ptr = memchr (buffer, '\n', ret);
if (ptr) if (ptr)
diff = ptr - buffer + 1; diff = ptr - buffer + 1;
else else
diff = ret; diff = ret;
whole_buffer_len += diff; whole_buffer_len += diff;
/* /*
* Don't allow the buffer to grow without bound. If we * Don't allow the buffer to grow without bound. If we
* get to more than MAXIMUM_BUFFER_LENGTH close. * get to more than MAXIMUM_BUFFER_LENGTH close.
*/ */
if (whole_buffer_len > MAXIMUM_BUFFER_LENGTH) { if (whole_buffer_len > MAXIMUM_BUFFER_LENGTH)
ret = -ERANGE; {
goto CLEANUP; ret = -ERANGE;
} goto CLEANUP;
}
line_ptr->data = safemalloc(diff); line_ptr->data = safemalloc (diff);
if (!line_ptr->data) { if (!line_ptr->data)
ret = -ENOMEM; {
goto CLEANUP; ret = -ENOMEM;
} goto CLEANUP;
}
recv(fd, line_ptr->data, diff, 0); recv (fd, line_ptr->data, diff, 0);
line_ptr->len = diff; line_ptr->len = diff;
if (ptr) { if (ptr)
line_ptr->next = NULL; {
break; line_ptr->next = NULL;
} break;
}
line_ptr->next = safecalloc(sizeof(struct read_lines_s), 1); line_ptr->next = safecalloc (sizeof (struct read_lines_s), 1);
if (!line_ptr->next) { if (!line_ptr->next)
ret = -ENOMEM; {
goto CLEANUP; ret = -ENOMEM;
} goto CLEANUP;
line_ptr = line_ptr->next; }
} line_ptr = line_ptr->next;
}
*whole_buffer = safemalloc(whole_buffer_len + 1); *whole_buffer = safemalloc (whole_buffer_len + 1);
if (!*whole_buffer) { if (!*whole_buffer)
ret = -ENOMEM; {
goto CLEANUP; ret = -ENOMEM;
} goto CLEANUP;
}
*(*whole_buffer + whole_buffer_len) = '\0'; *(*whole_buffer + whole_buffer_len) = '\0';
whole_buffer_len = 0; whole_buffer_len = 0;
line_ptr = first_line; line_ptr = first_line;
while (line_ptr) { while (line_ptr)
memcpy(*whole_buffer + whole_buffer_len, line_ptr->data, {
line_ptr->len); memcpy (*whole_buffer + whole_buffer_len, line_ptr->data,
whole_buffer_len += line_ptr->len; line_ptr->len);
whole_buffer_len += line_ptr->len;
line_ptr = line_ptr->next; line_ptr = line_ptr->next;
} }
ret = whole_buffer_len; ret = whole_buffer_len;
CLEANUP: CLEANUP:
do { do
line_ptr = first_line->next; {
if (first_line->data) line_ptr = first_line->next;
safefree(first_line->data); if (first_line->data)
safefree(first_line); safefree (first_line->data);
first_line = line_ptr; safefree (first_line);
} while (first_line); first_line = line_ptr;
}
while (first_line);
return ret; return ret;
} }
/* /*
@ -246,32 +264,35 @@ readline(int fd, char **whole_buffer)
* hex string. * hex string.
*/ */
char * char *
get_ip_string(struct sockaddr *sa, char *buf, size_t buflen) get_ip_string (struct sockaddr *sa, char *buf, size_t buflen)
{ {
assert(sa != NULL); assert (sa != NULL);
assert(buf != NULL); assert (buf != NULL);
assert(buflen != 0); assert (buflen != 0);
buf[0] = '\0'; /* start with an empty string */ buf[0] = '\0'; /* start with an empty string */
switch (sa->sa_family) { switch (sa->sa_family)
case AF_INET:{ {
struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; case AF_INET:
{
struct sockaddr_in *sa_in = (struct sockaddr_in *) sa;
inet_ntop(AF_INET, &sa_in->sin_addr, buf, buflen); inet_ntop (AF_INET, &sa_in->sin_addr, buf, buflen);
break; break;
} }
case AF_INET6:{ case AF_INET6:
struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; {
struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *) sa;
inet_ntop(AF_INET6, &sa_in6->sin6_addr, buf, buflen); inet_ntop (AF_INET6, &sa_in6->sin6_addr, buf, buflen);
break; break;
} }
default: default:
/* no valid family */ /* no valid family */
return NULL; return NULL;
} }
return buf; return buf;
} }
/* /*
@ -282,41 +303,42 @@ get_ip_string(struct sockaddr *sa, char *buf, size_t buflen)
* Returns the same as inet_pton(). * Returns the same as inet_pton().
*/ */
int int
full_inet_pton(const char *ip, void *dst) full_inet_pton (const char *ip, void *dst)
{ {
char buf[24], tmp[24]; /* IPv4->IPv6 = ::FFFF:xxx.xxx.xxx.xxx\0 */ char buf[24], tmp[24]; /* IPv4->IPv6 = ::FFFF:xxx.xxx.xxx.xxx\0 */
int n; int n;
assert(ip != NULL && strlen(ip) != 0); assert (ip != NULL && strlen (ip) != 0);
assert(dst != NULL); assert (dst != NULL);
/* /*
* Check if the string is an IPv4 numeric address. We use the * Check if the string is an IPv4 numeric address. We use the
* older inet_aton() call since it handles more IPv4 numeric * older inet_aton() call since it handles more IPv4 numeric
* address formats. * address formats.
*/ */
n = inet_aton(ip, (struct in_addr *)dst); n = inet_aton (ip, (struct in_addr *) dst);
if (n == 0) { if (n == 0)
/* {
* Simple case: "ip" wasn't an IPv4 numeric address, so /*
* try doing the conversion as an IPv6 address. This * Simple case: "ip" wasn't an IPv4 numeric address, so
* will either succeed or fail, but we can't do any * try doing the conversion as an IPv6 address. This
* more processing anyway. * will either succeed or fail, but we can't do any
*/ * more processing anyway.
return inet_pton(AF_INET6, ip, dst); */
} return inet_pton (AF_INET6, ip, dst);
}
/* /*
* "ip" was an IPv4 address, so we need to convert it to * "ip" was an IPv4 address, so we need to convert it to
* an IPv4-mapped IPv6 address and do the conversion * an IPv4-mapped IPv6 address and do the conversion
* again to get the IPv6 network structure. * again to get the IPv6 network structure.
* *
* We convert the IPv4 binary address back into the * We convert the IPv4 binary address back into the
* standard dotted-decimal format using inet_ntop() * standard dotted-decimal format using inet_ntop()
* so we can be sure that inet_pton will accept the * so we can be sure that inet_pton will accept the
* full string. * full string.
*/ */
snprintf(buf, sizeof(buf), "::ffff:%s", snprintf (buf, sizeof (buf), "::ffff:%s",
inet_ntop(AF_INET, dst, tmp, sizeof(tmp))); inet_ntop (AF_INET, dst, tmp, sizeof (tmp)));
return inet_pton(AF_INET6, buf, dst); return inet_pton (AF_INET6, buf, dst);
} }

View File

@ -21,13 +21,13 @@
#ifndef TINYPROXY_NETWORK_H #ifndef TINYPROXY_NETWORK_H
#define TINYPROXY_NETWORK_H #define TINYPROXY_NETWORK_H
extern ssize_t safe_write(int fd, const char *buffer, size_t count); extern ssize_t safe_write (int fd, const char *buffer, size_t count);
extern ssize_t safe_read(int fd, char *buffer, size_t count); extern ssize_t safe_read (int fd, char *buffer, size_t count);
extern int write_message(int fd, const char *fmt, ...); extern int write_message (int fd, const char *fmt, ...);
extern ssize_t readline(int fd, char **whole_buffer); extern ssize_t readline (int fd, char **whole_buffer);
extern char *get_ip_string(struct sockaddr *sa, char *buf, size_t len); extern char *get_ip_string (struct sockaddr *sa, char *buf, size_t len);
extern int full_inet_pton(const char *ip, void *dst); extern int full_inet_pton (const char *ip, void *dst);
#endif #endif

2385
src/reqs.c

File diff suppressed because it is too large Load Diff

View File

@ -34,18 +34,19 @@
/* /*
* This structure holds the information pulled from a URL request. * This structure holds the information pulled from a URL request.
*/ */
struct request_s { struct request_s
char *method; {
char *protocol; char *method;
char *protocol;
char *host; char *host;
uint16_t port; uint16_t port;
char *path; char *path;
}; };
extern void handle_connection(int fd); extern void handle_connection (int fd);
extern void add_connect_port_allowed(int port); extern void add_connect_port_allowed (int port);
extern void upstream_add(const char *host, int port, const char *domain); extern void upstream_add (const char *host, int port, const char *domain);
#endif #endif

View File

@ -30,128 +30,132 @@
* Add entry to the reversepath list * Add entry to the reversepath list
*/ */
void void
reversepath_add(const char *path, const char *url) reversepath_add (const char *path, const char *url)
{ {
struct reversepath *reverse; struct reversepath *reverse;
if (url == NULL) { if (url == NULL)
log_message(LOG_WARNING, {
"Illegal reverse proxy rule: missing url"); log_message (LOG_WARNING, "Illegal reverse proxy rule: missing url");
return; return;
} }
if (!strstr(url, "://")) { if (!strstr (url, "://"))
log_message(LOG_WARNING, {
"Skipping reverse proxy rule: '%s' is not a valid url", log_message (LOG_WARNING,
url); "Skipping reverse proxy rule: '%s' is not a valid url",
return; url);
} return;
}
if (path && *path != '/') { if (path && *path != '/')
log_message(LOG_WARNING, {
"Skipping reverse proxy rule: path '%s' doesn't start with a /", log_message (LOG_WARNING,
path); "Skipping reverse proxy rule: path '%s' doesn't start with a /",
return; path);
} return;
}
if (!(reverse = safemalloc(sizeof(struct reversepath)))) { if (!(reverse = safemalloc (sizeof (struct reversepath))))
log_message(LOG_ERR, {
"Unable to allocate memory in reversepath_add()"); log_message (LOG_ERR, "Unable to allocate memory in reversepath_add()");
return; return;
} }
if (!path) if (!path)
reverse->path = safestrdup("/"); reverse->path = safestrdup ("/");
else else
reverse->path = safestrdup(path); reverse->path = safestrdup (path);
reverse->url = safestrdup(url); reverse->url = safestrdup (url);
reverse->next = config.reversepath_list; reverse->next = config.reversepath_list;
config.reversepath_list = reverse; config.reversepath_list = reverse;
log_message(LOG_INFO, log_message (LOG_INFO,
"Added reverse proxy rule: %s -> %s", reverse->path, "Added reverse proxy rule: %s -> %s", reverse->path,
reverse->url); reverse->url);
} }
/* /*
* Check if a request url is in the reversepath list * Check if a request url is in the reversepath list
*/ */
struct reversepath * struct reversepath *
reversepath_get(char *url) reversepath_get (char *url)
{ {
struct reversepath *reverse = config.reversepath_list; struct reversepath *reverse = config.reversepath_list;
while (reverse) { while (reverse)
if (strstr(url, reverse->path) == url) {
return reverse; if (strstr (url, reverse->path) == url)
return reverse;
reverse = reverse->next; reverse = reverse->next;
} }
return NULL; return NULL;
} }
/* /*
* Rewrite the URL for reverse proxying. * Rewrite the URL for reverse proxying.
*/ */
char * char *
reverse_rewrite_url(struct conn_s *connptr, hashmap_t hashofheaders, char *url) reverse_rewrite_url (struct conn_s *connptr, hashmap_t hashofheaders,
char *url)
{ {
char *rewrite_url = NULL; char *rewrite_url = NULL;
char *cookie = NULL; char *cookie = NULL;
char *cookieval; char *cookieval;
struct reversepath *reverse; struct reversepath *reverse;
/* Reverse requests always start with a slash */ /* Reverse requests always start with a slash */
if (*url == '/') { if (*url == '/')
/* First try locating the reverse mapping by request url */ {
reverse = reversepath_get(url); /* First try locating the reverse mapping by request url */
if (reverse) { reverse = reversepath_get (url);
rewrite_url = safemalloc(strlen(url) + if (reverse)
strlen(reverse->url) + 1); {
strcpy(rewrite_url, reverse->url); rewrite_url = safemalloc (strlen (url) + strlen (reverse->url) + 1);
strcat(rewrite_url, url + strlen(reverse->path)); strcpy (rewrite_url, reverse->url);
} else if (config.reversemagic strcat (rewrite_url, url + strlen (reverse->path));
&& hashmap_entry_by_key(hashofheaders, }
"cookie", else if (config.reversemagic
(void **)&cookie) > 0) { && hashmap_entry_by_key (hashofheaders,
"cookie", (void **) &cookie) > 0)
{
/* No match - try the magical tracking cookie next */ /* No match - try the magical tracking cookie next */
if ((cookieval = strstr(cookie, REVERSE_COOKIE "=")) if ((cookieval = strstr (cookie, REVERSE_COOKIE "="))
&& (reverse = && (reverse =
reversepath_get(cookieval + reversepath_get (cookieval + strlen (REVERSE_COOKIE) + 1)))
strlen(REVERSE_COOKIE) + 1))) { {
rewrite_url = safemalloc(strlen(url) + rewrite_url = safemalloc (strlen (url) +
strlen strlen (reverse->url) + 1);
(reverse->url) + 1); strcpy (rewrite_url, reverse->url);
strcpy(rewrite_url, reverse->url); strcat (rewrite_url, url + 1);
strcat(rewrite_url, url + 1);
log_message(LOG_INFO, log_message (LOG_INFO,
"Magical tracking cookie says: %s", "Magical tracking cookie says: %s", reverse->path);
reverse->path); }
} }
} }
}
/* Forward proxy support off and no reverse path match found */ /* Forward proxy support off and no reverse path match found */
if (config.reverseonly && !rewrite_url) { if (config.reverseonly && !rewrite_url)
log_message(LOG_ERR, "Bad request"); {
indicate_http_error(connptr, 400, "Bad Request", log_message (LOG_ERR, "Bad request");
"detail", indicate_http_error (connptr, 400, "Bad Request",
"Request has an invalid URL", "url", "detail",
url, NULL); "Request has an invalid URL", "url", url, NULL);
return NULL; return NULL;
} }
log_message(LOG_CONN, "Rewriting URL: %s -> %s", url, rewrite_url); log_message (LOG_CONN, "Rewriting URL: %s -> %s", url, rewrite_url);
/* Store reverse path so that the magical tracking cookie can be set */ /* Store reverse path so that the magical tracking cookie can be set */
if (config.reversemagic) if (config.reversemagic)
connptr->reversepath = safestrdup(reverse->path); connptr->reversepath = safestrdup (reverse->path);
return rewrite_url; return rewrite_url;
} }

View File

@ -23,17 +23,18 @@
#include "conns.h" #include "conns.h"
struct reversepath { struct reversepath
struct reversepath *next; {
char *path; struct reversepath *next;
char *url; char *path;
char *url;
}; };
#define REVERSE_COOKIE "yummy_magical_cookie" #define REVERSE_COOKIE "yummy_magical_cookie"
extern void reversepath_add(const char *path, const char *url); extern void reversepath_add (const char *path, const char *url);
extern struct reversepath *reversepath_get(char *url); extern struct reversepath *reversepath_get (char *url);
extern char *reverse_rewrite_url(struct conn_s *connptr, extern char *reverse_rewrite_url (struct conn_s *connptr,
hashmap_t hashofheaders, char *url); hashmap_t hashofheaders, char *url);
#endif #endif

View File

@ -39,34 +39,36 @@
* to indicate an error. * to indicate an error.
*/ */
static int static int
bind_socket(int sockfd, const char *addr) bind_socket (int sockfd, const char *addr)
{ {
struct addrinfo hints, *res, *ressave; struct addrinfo hints, *res, *ressave;
assert(sockfd >= 0); assert (sockfd >= 0);
assert(addr != NULL && strlen(addr) != 0); assert (addr != NULL && strlen (addr) != 0);
memset(&hints, 0, sizeof(struct addrinfo)); memset (&hints, 0, sizeof (struct addrinfo));
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
/* The local port it not important */ /* The local port it not important */
if (getaddrinfo(addr, NULL, &hints, &res) != 0) if (getaddrinfo (addr, NULL, &hints, &res) != 0)
return -1; return -1;
ressave = res; ressave = res;
/* Loop through the addresses and try to bind to each */ /* Loop through the addresses and try to bind to each */
do { do
if (bind(sockfd, res->ai_addr, res->ai_addrlen) == 0) {
break; /* success */ if (bind (sockfd, res->ai_addr, res->ai_addrlen) == 0)
} while ((res = res->ai_next) != NULL); break; /* success */
}
while ((res = res->ai_next) != NULL);
freeaddrinfo(ressave); freeaddrinfo (ressave);
if (res == NULL) /* was not able to bind to any address */ if (res == NULL) /* was not able to bind to any address */
return -1; return -1;
return sockfd; return sockfd;
} }
/* /*
@ -75,91 +77,97 @@ bind_socket(int sockfd, const char *addr)
* independent implementation (mostly for IPv4 and IPv6 addresses.) * independent implementation (mostly for IPv4 and IPv6 addresses.)
*/ */
int int
opensock(const char *host, int port, const char *bind_to) opensock (const char *host, int port, const char *bind_to)
{ {
int sockfd, n; int sockfd, n;
struct addrinfo hints, *res, *ressave; struct addrinfo hints, *res, *ressave;
char portstr[6]; char portstr[6];
assert(host != NULL); assert (host != NULL);
assert(port > 0); assert (port > 0);
memset(&hints, 0, sizeof(struct addrinfo)); memset (&hints, 0, sizeof (struct addrinfo));
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
snprintf(portstr, sizeof(portstr), "%d", port); snprintf (portstr, sizeof (portstr), "%d", port);
n = getaddrinfo(host, portstr, &hints, &res); n = getaddrinfo (host, portstr, &hints, &res);
if (n != 0) { if (n != 0)
log_message(LOG_ERR, "opensock: Could not retrieve info for %s", {
host); log_message (LOG_ERR, "opensock: Could not retrieve info for %s", host);
return -1; return -1;
} }
ressave = res; ressave = res;
do { do
sockfd = {
socket(res->ai_family, res->ai_socktype, res->ai_protocol); sockfd = socket (res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd < 0) if (sockfd < 0)
continue; /* ignore this one */ continue; /* ignore this one */
/* Bind to the specified address */ /* Bind to the specified address */
if (bind_to) { if (bind_to)
if (bind_socket(sockfd, bind_to) < 0) { {
close(sockfd); if (bind_socket (sockfd, bind_to) < 0)
continue; /* can't bind, so try again */ {
} close (sockfd);
} else if (config.bind_address) { continue; /* can't bind, so try again */
if (bind_socket(sockfd, config.bind_address) < 0) { }
close(sockfd); }
continue; /* can't bind, so try again */ else if (config.bind_address)
} {
} if (bind_socket (sockfd, config.bind_address) < 0)
{
close (sockfd);
continue; /* can't bind, so try again */
}
}
if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0) if (connect (sockfd, res->ai_addr, res->ai_addrlen) == 0)
break; /* success */ break; /* success */
close(sockfd); close (sockfd);
} while ((res = res->ai_next) != NULL); }
while ((res = res->ai_next) != NULL);
freeaddrinfo(ressave); freeaddrinfo (ressave);
if (res == NULL) { if (res == NULL)
log_message(LOG_ERR, {
"opensock: Could not establish a connection to %s", log_message (LOG_ERR,
host); "opensock: Could not establish a connection to %s", host);
return -1; return -1;
} }
return sockfd; return sockfd;
} }
/* /*
* Set the socket to non blocking -rjkaes * Set the socket to non blocking -rjkaes
*/ */
int int
socket_nonblocking(int sock) socket_nonblocking (int sock)
{ {
int flags; int flags;
assert(sock >= 0); assert (sock >= 0);
flags = fcntl(sock, F_GETFL, 0); flags = fcntl (sock, F_GETFL, 0);
return fcntl(sock, F_SETFL, flags | O_NONBLOCK); return fcntl (sock, F_SETFL, flags | O_NONBLOCK);
} }
/* /*
* Set the socket to blocking -rjkaes * Set the socket to blocking -rjkaes
*/ */
int int
socket_blocking(int sock) socket_blocking (int sock)
{ {
int flags; int flags;
assert(sock >= 0); assert (sock >= 0);
flags = fcntl(sock, F_GETFL, 0); flags = fcntl (sock, F_GETFL, 0);
return fcntl(sock, F_SETFL, flags & ~O_NONBLOCK); return fcntl (sock, F_SETFL, flags & ~O_NONBLOCK);
} }
/* /*
@ -169,95 +177,101 @@ socket_blocking(int sock)
* - rjkaes * - rjkaes
*/ */
int int
listen_sock(uint16_t port, socklen_t * addrlen) listen_sock (uint16_t port, socklen_t * addrlen)
{ {
int listenfd; int listenfd;
const int on = 1; const int on = 1;
struct sockaddr_in addr; struct sockaddr_in addr;
assert(port > 0); assert (port > 0);
assert(addrlen != NULL); assert (addrlen != NULL);
listenfd = socket(AF_INET, SOCK_STREAM, 0); listenfd = socket (AF_INET, SOCK_STREAM, 0);
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); setsockopt (listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on));
memset(&addr, 0, sizeof(addr)); memset (&addr, 0, sizeof (addr));
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_port = htons(port); addr.sin_port = htons (port);
if (config.ipAddr) { if (config.ipAddr)
addr.sin_addr.s_addr = inet_addr(config.ipAddr); {
} else { addr.sin_addr.s_addr = inet_addr (config.ipAddr);
addr.sin_addr.s_addr = inet_addr("0.0.0.0"); }
} else
{
addr.sin_addr.s_addr = inet_addr ("0.0.0.0");
}
if (bind(listenfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { if (bind (listenfd, (struct sockaddr *) &addr, sizeof (addr)) < 0)
log_message(LOG_ERR, {
"Unable to bind listening socket because of %s", log_message (LOG_ERR,
strerror(errno)); "Unable to bind listening socket because of %s",
return -1; strerror (errno));
} return -1;
}
if (listen(listenfd, MAXLISTEN) < 0) { if (listen (listenfd, MAXLISTEN) < 0)
log_message(LOG_ERR, {
"Unable to start listening socket because of %s", log_message (LOG_ERR,
strerror(errno)); "Unable to start listening socket because of %s",
return -1; strerror (errno));
} return -1;
}
*addrlen = sizeof(addr); *addrlen = sizeof (addr);
return listenfd; return listenfd;
} }
/* /*
* Takes a socket descriptor and returns the socket's IP address. * Takes a socket descriptor and returns the socket's IP address.
*/ */
int int
getsock_ip(int fd, char *ipaddr) getsock_ip (int fd, char *ipaddr)
{ {
struct sockaddr_storage name; struct sockaddr_storage name;
socklen_t namelen = sizeof(name); socklen_t namelen = sizeof (name);
assert(fd >= 0); assert (fd >= 0);
if (getsockname(fd, (struct sockaddr *)&name, &namelen) != 0) { if (getsockname (fd, (struct sockaddr *) &name, &namelen) != 0)
log_message(LOG_ERR, "getsock_ip: getsockname() error: %s", {
strerror(errno)); log_message (LOG_ERR, "getsock_ip: getsockname() error: %s",
return -1; strerror (errno));
} return -1;
}
if (get_ip_string((struct sockaddr *)&name, ipaddr, IP_LENGTH) == NULL) if (get_ip_string ((struct sockaddr *) &name, ipaddr, IP_LENGTH) == NULL)
return -1; return -1;
return 0; return 0;
} }
/* /*
* Return the peer's socket information. * Return the peer's socket information.
*/ */
int int
getpeer_information(int fd, char *ipaddr, char *string_addr) getpeer_information (int fd, char *ipaddr, char *string_addr)
{ {
struct sockaddr_storage sa; struct sockaddr_storage sa;
socklen_t salen = sizeof sa; socklen_t salen = sizeof sa;
assert(fd >= 0); assert (fd >= 0);
assert(ipaddr != NULL); assert (ipaddr != NULL);
assert(string_addr != NULL); assert (string_addr != NULL);
/* Set the strings to default values */ /* Set the strings to default values */
ipaddr[0] = '\0'; ipaddr[0] = '\0';
strlcpy(string_addr, "[unknown]", HOSTNAME_LENGTH); strlcpy (string_addr, "[unknown]", HOSTNAME_LENGTH);
/* Look up the IP address */ /* Look up the IP address */
if (getpeername(fd, (struct sockaddr *) &sa, &salen) != 0) if (getpeername (fd, (struct sockaddr *) &sa, &salen) != 0)
return -1; return -1;
if (get_ip_string((struct sockaddr *)&sa, ipaddr, IP_LENGTH) == NULL) if (get_ip_string ((struct sockaddr *) &sa, ipaddr, IP_LENGTH) == NULL)
return -1; return -1;
/* Get the full host name */ /* Get the full host name */
return getnameinfo((struct sockaddr *)&sa, salen, return getnameinfo ((struct sockaddr *) &sa, salen,
string_addr, HOSTNAME_LENGTH, NULL, 0, 0); string_addr, HOSTNAME_LENGTH, NULL, 0, 0);
} }

View File

@ -28,13 +28,13 @@
#define MAXLINE (1024 * 4) #define MAXLINE (1024 * 4)
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(uint16_t port, socklen_t * addrlen); extern int listen_sock (uint16_t port, socklen_t * addrlen);
extern int socket_nonblocking(int sock); 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 int getpeer_information (int fd, char *ipaddr, char *string_addr);
#endif #endif

View File

@ -33,12 +33,13 @@
#include "stats.h" #include "stats.h"
#include "utils.h" #include "utils.h"
struct stat_s { struct stat_s
unsigned long int num_reqs; {
unsigned long int num_badcons; unsigned long int num_reqs;
unsigned long int num_open; unsigned long int num_badcons;
unsigned long int num_refused; unsigned long int num_open;
unsigned long int num_denied; unsigned long int num_refused;
unsigned long int num_denied;
}; };
static struct stat_s *stats; static struct stat_s *stats;
@ -47,83 +48,82 @@ static struct stat_s *stats;
* Initialize the statistics information to zero. * Initialize the statistics information to zero.
*/ */
void void
init_stats(void) init_stats (void)
{ {
stats = malloc_shared_memory(sizeof(struct stat_s)); stats = malloc_shared_memory (sizeof (struct stat_s));
if (stats == MAP_FAILED) if (stats == MAP_FAILED)
return; return;
memset(stats, 0, sizeof(struct stat_s)); memset (stats, 0, sizeof (struct stat_s));
} }
/* /*
* Display the statics of the tinyproxy server. * Display the statics of the tinyproxy server.
*/ */
int int
showstats(struct conn_s *connptr) showstats (struct conn_s *connptr)
{ {
static char *msg = static char *msg =
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
"<html>\n" "<html>\n"
"<head><title>%s version %s run-time statistics</title></head>\n" "<head><title>%s version %s run-time statistics</title></head>\n"
"<body>\n" "<body>\n"
"<h1>%s version %s run-time statistics</h1>\n" "<h1>%s version %s run-time statistics</h1>\n"
"<p>\n" "<p>\n"
"Number of open connections: %lu<br />\n" "Number of open connections: %lu<br />\n"
"Number of requests: %lu<br />\n" "Number of requests: %lu<br />\n"
"Number of bad connections: %lu<br />\n" "Number of bad connections: %lu<br />\n"
"Number of denied connections: %lu<br />\n" "Number of denied connections: %lu<br />\n"
"Number of refused connections due to high load: %lu\n" "Number of refused connections due to high load: %lu\n"
"</p>\n" "</p>\n"
"<hr />\n" "<hr />\n"
"<p><em>Generated by %s version %s.</em></p>\n" "<p><em>Generated by %s version %s.</em></p>\n" "</body>\n" "</html>\n";
"</body>\n"
"</html>\n";
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];
FILE *statfile; FILE *statfile;
snprintf(opens, sizeof(opens), "%lu", stats->num_open); snprintf (opens, sizeof (opens), "%lu", stats->num_open);
snprintf(reqs, sizeof(reqs), "%lu", stats->num_reqs); snprintf (reqs, sizeof (reqs), "%lu", stats->num_reqs);
snprintf(badconns, sizeof(badconns), "%lu", stats->num_badcons); snprintf (badconns, sizeof (badconns), "%lu", stats->num_badcons);
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);
if (!config.statpage || (!(statfile = fopen(config.statpage, "r")))) { if (!config.statpage || (!(statfile = fopen (config.statpage, "r"))))
message_buffer = safemalloc(MAXBUFFSIZE); {
if (!message_buffer) message_buffer = safemalloc (MAXBUFFSIZE);
return -1; if (!message_buffer)
return -1;
snprintf(message_buffer, MAXBUFFSIZE, msg, snprintf (message_buffer, MAXBUFFSIZE, msg,
PACKAGE, VERSION, PACKAGE, VERSION, PACKAGE, VERSION, PACKAGE, VERSION,
stats->num_open, stats->num_open,
stats->num_reqs, stats->num_reqs,
stats->num_badcons, stats->num_denied, stats->num_badcons, stats->num_denied,
stats->num_refused, stats->num_refused, PACKAGE, VERSION);
PACKAGE, VERSION);
if (send_http_message(connptr, 200, "OK", message_buffer) < 0) { if (send_http_message (connptr, 200, "OK", message_buffer) < 0)
safefree(message_buffer); {
return -1; safefree (message_buffer);
} return -1;
}
safefree(message_buffer); safefree (message_buffer);
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);
add_error_variable(connptr, "deniedconns", denied); add_error_variable (connptr, "deniedconns", denied);
add_error_variable(connptr, "refusedconns", refused); add_error_variable (connptr, "refusedconns", refused);
add_standard_vars(connptr); add_standard_vars (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);
return 0; return 0;
} }
/* /*
@ -131,28 +131,29 @@ showstats(struct conn_s *connptr)
* stats.h * stats.h
*/ */
int int
update_stats(status_t update_level) update_stats (status_t update_level)
{ {
switch (update_level) { switch (update_level)
case STAT_BADCONN: {
++stats->num_badcons; case STAT_BADCONN:
break; ++stats->num_badcons;
case STAT_OPEN: break;
++stats->num_open; case STAT_OPEN:
++stats->num_reqs; ++stats->num_open;
break; ++stats->num_reqs;
case STAT_CLOSE: break;
--stats->num_open; case STAT_CLOSE:
break; --stats->num_open;
case STAT_REFUSE: break;
++stats->num_refused; case STAT_REFUSE:
break; ++stats->num_refused;
case STAT_DENIED: break;
++stats->num_denied; case STAT_DENIED:
break; ++stats->num_denied;
default: break;
return -1; default:
} return -1;
}
return 0; return 0;
} }

View File

@ -26,19 +26,20 @@
/* /*
* Various logable statistics * Various logable statistics
*/ */
typedef enum { typedef enum
STAT_BADCONN, /* bad connection, for unknown reason */ {
STAT_OPEN, /* connection opened */ STAT_BADCONN, /* bad connection, for unknown reason */
STAT_CLOSE, /* connection closed */ STAT_OPEN, /* connection opened */
STAT_REFUSE, /* connection refused (to outside world) */ STAT_CLOSE, /* connection closed */
STAT_DENIED /* connection denied to tinyproxy itself */ STAT_REFUSE, /* connection refused (to outside world) */
STAT_DENIED /* connection denied to tinyproxy itself */
} status_t; } status_t;
/* /*
* Public API to the statistics for tinyproxy * Public API to the statistics for tinyproxy
*/ */
extern void init_stats(void); extern void init_stats (void);
extern int showstats(struct conn_s *connptr); extern int showstats (struct conn_s *connptr);
extern int update_stats(status_t update_level); extern int update_stats (status_t update_level);
#endif #endif

View File

@ -33,18 +33,18 @@
* destination buffer. * destination buffer.
*/ */
size_t size_t
strlcpy(char *dst, const char *src, size_t size) strlcpy (char *dst, const char *src, size_t size)
{ {
size_t len = strlen(src); size_t len = strlen (src);
size_t ret = len; size_t ret = len;
if (len >= size) if (len >= size)
len = size - 1; len = size - 1;
memcpy(dst, src, len); memcpy (dst, src, len);
dst[len] = '\0'; dst[len] = '\0';
return ret; return ret;
} }
#endif #endif
@ -56,20 +56,21 @@ strlcpy(char *dst, const char *src, size_t size)
* length. * length.
*/ */
size_t size_t
strlcat(char *dst, const char *src, size_t size) strlcat (char *dst, const char *src, size_t size)
{ {
size_t len1 = strlen(dst); size_t len1 = strlen (dst);
size_t len2 = strlen(src); size_t len2 = strlen (src);
size_t ret = len1 + len2; size_t ret = len1 + len2;
if (len1 + len2 >= size) if (len1 + len2 >= size)
len2 = size - len1 - 1; len2 = size - len1 - 1;
if (len2 > 0) { if (len2 > 0)
memcpy(dst + len1, src, len2); {
dst[len1 + len2] = '\0'; memcpy (dst + len1, src, len2);
} dst[len1 + len2] = '\0';
}
return ret; return ret;
} }
#endif #endif
@ -83,30 +84,31 @@ strlcat(char *dst, const char *src, size_t size)
* negative return value indicates an error. * negative return value indicates an error.
*/ */
ssize_t ssize_t
chomp(char *buffer, size_t length) chomp (char *buffer, size_t length)
{ {
size_t chars; size_t chars;
assert(buffer != NULL); assert (buffer != NULL);
assert(length > 0); assert (length > 0);
/* Make sure the arguments are valid */ /* Make sure the arguments are valid */
if (buffer == NULL) if (buffer == NULL)
return -EFAULT; return -EFAULT;
if (length < 1) if (length < 1)
return -ERANGE; return -ERANGE;
chars = 0; chars = 0;
--length; --length;
while (buffer[length] == '\r' || buffer[length] == '\n') { while (buffer[length] == '\r' || buffer[length] == '\n')
buffer[length] = '\0'; {
chars++; buffer[length] = '\0';
chars++;
/* Stop once we get to zero to prevent wrap-around */ /* Stop once we get to zero to prevent wrap-around */
if (length-- == 0) if (length-- == 0)
break; break;
} }
return chars; return chars;
} }

View File

@ -22,13 +22,13 @@
#define TINYPROXY_TEXT_H #define TINYPROXY_TEXT_H
#ifndef HAVE_STRLCAT #ifndef HAVE_STRLCAT
extern size_t strlcat(char *dst, const char *src, size_t size); extern size_t strlcat (char *dst, const char *src, size_t size);
#endif /* HAVE_STRLCAT */ #endif /* HAVE_STRLCAT */
#ifndef HAVE_STRLCPY #ifndef HAVE_STRLCPY
extern size_t strlcpy(char *dst, const char *src, size_t size); extern size_t strlcpy (char *dst, const char *src, size_t size);
#endif /* HAVE_STRLCPY */ #endif /* HAVE_STRLCPY */
extern ssize_t chomp(char *buffer, size_t length); extern ssize_t chomp (char *buffer, size_t length);
#endif #endif

View File

@ -41,60 +41,61 @@
#include "stats.h" #include "stats.h"
#include "utils.h" #include "utils.h"
RETSIGTYPE takesig(int sig); RETSIGTYPE takesig (int sig);
/* /*
* Global Structures * Global Structures
*/ */
struct config_s config; struct config_s config;
float load = 0.00; float load = 0.00;
unsigned int received_sighup = FALSE; /* boolean */ unsigned int received_sighup = FALSE; /* boolean */
unsigned int processed_config_file = FALSE; /* boolean */ unsigned int processed_config_file = FALSE; /* boolean */
/* /*
* Handle a signal * Handle a signal
*/ */
RETSIGTYPE RETSIGTYPE
takesig(int sig) takesig (int sig)
{ {
pid_t pid; pid_t pid;
int status; int status;
switch (sig) { switch (sig)
case SIGHUP: {
received_sighup = TRUE; case SIGHUP:
break; received_sighup = TRUE;
break;
case SIGTERM: case SIGTERM:
config.quit = TRUE; config.quit = TRUE;
break; break;
case SIGCHLD: case SIGCHLD:
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) ; while ((pid = waitpid (-1, &status, WNOHANG)) > 0);
break; break;
} }
return; return;
} }
/* /*
* Display the version information for the user. * Display the version information for the user.
*/ */
static void static void
display_version(void) display_version (void)
{ {
printf("%s %s (%s)\n", PACKAGE, VERSION, TARGET_SYSTEM); printf ("%s %s (%s)\n", PACKAGE, VERSION, TARGET_SYSTEM);
} }
/* /*
* Display the copyright and license for this program. * Display the copyright and license for this program.
*/ */
static void static void
display_license(void) display_license (void)
{ {
display_version(); display_version ();
printf("\ printf ("\
Copyright 1998 Steven Young (sdyoung@well.com)\n\ Copyright 1998 Steven Young (sdyoung@well.com)\n\
Copyright 1998-2002 Robert James Kaes (rjkaes@users.sourceforge.net)\n\ Copyright 1998-2002 Robert James Kaes (rjkaes@users.sourceforge.net)\n\
Copyright 1999 George Talusan (gstalusan@uwaterloo.ca)\n\ Copyright 1999 George Talusan (gstalusan@uwaterloo.ca)\n\
@ -119,10 +120,10 @@ display_license(void)
* Display usage to the user. * Display usage to the user.
*/ */
static void static void
display_usage(void) display_usage (void)
{ {
printf("Usage: %s [options]\n", PACKAGE); printf ("Usage: %s [options]\n", PACKAGE);
printf("\ printf ("\
Options:\n\ Options:\n\
-d Operate in DEBUG mode.\n\ -d Operate in DEBUG mode.\n\
-c FILE Use an alternate configuration file.\n\ -c FILE Use an alternate configuration file.\n\
@ -130,319 +131,344 @@ Options:\n\
-l Display the license.\n\ -l Display the license.\n\
-v Display the version number.\n"); -v Display the version number.\n");
/* Display the modes compiled into tinyproxy */ /* Display the modes compiled into tinyproxy */
printf("\nFeatures compiled in:\n"); printf ("\nFeatures compiled in:\n");
#ifdef XTINYPROXY_ENABLE #ifdef XTINYPROXY_ENABLE
printf(" XTinyproxy header\n"); printf (" XTinyproxy header\n");
#endif /* XTINYPROXY */ #endif /* XTINYPROXY */
#ifdef FILTER_ENABLE #ifdef FILTER_ENABLE
printf(" Filtering\n"); printf (" Filtering\n");
#endif /* FILTER_ENABLE */ #endif /* FILTER_ENABLE */
#ifndef NDEBUG #ifndef NDEBUG
printf(" Debugging code\n"); printf (" Debugging code\n");
#endif /* NDEBUG */ #endif /* NDEBUG */
#ifdef TRANSPARENT_PROXY #ifdef TRANSPARENT_PROXY
printf(" Transparent proxy support\n"); printf (" Transparent proxy support\n");
#endif /* TRANSPARENT_PROXY */ #endif /* TRANSPARENT_PROXY */
#ifdef REVERSE_SUPPORT #ifdef REVERSE_SUPPORT
printf(" Reverse proxy support\n"); printf (" Reverse proxy support\n");
#endif /* REVERSE_SUPPORT */ #endif /* REVERSE_SUPPORT */
} }
static int static int
get_id (char *str) get_id (char *str)
{ {
char *tstr; char *tstr;
if (str == NULL) if (str == NULL)
return -1; return -1;
tstr = str; tstr = str;
while (*tstr != 0) { while (*tstr != 0)
if (!isdigit(*tstr)) {
return -1; if (!isdigit (*tstr))
tstr++; return -1;
} tstr++;
}
return atoi(str); return atoi (str);
} }
int int
main(int argc, char **argv) main (int argc, char **argv)
{ {
int optch; int optch;
unsigned int godaemon = TRUE; /* boolean */ unsigned int godaemon = TRUE; /* boolean */
struct passwd *thisuser = NULL; struct passwd *thisuser = NULL;
struct group *thisgroup = NULL; struct group *thisgroup = NULL;
FILE *config_file; FILE *config_file;
/* 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.
*/ */
umask(0177); umask (0177);
/* Default configuration file location */ /* Default configuration file location */
config.config_file = DEFAULT_CONF_FILE; config.config_file = DEFAULT_CONF_FILE;
/* /*
* Process the various options * Process the various options
*/ */
while ((optch = getopt(argc, argv, "c:vldh")) != EOF) { while ((optch = getopt (argc, argv, "c:vldh")) != EOF)
switch (optch) { {
case 'v': switch (optch)
display_version(); {
exit(EX_OK); case 'v':
case 'l': display_version ();
display_license(); exit (EX_OK);
exit(EX_OK); case 'l':
case 'd': display_license ();
godaemon = FALSE; exit (EX_OK);
break; case 'd':
case 'c': godaemon = FALSE;
config.config_file = safestrdup(optarg); break;
if (!config.config_file) { case 'c':
fprintf(stderr, config.config_file = safestrdup (optarg);
"%s: Could not allocate memory.\n", if (!config.config_file)
argv[0]); {
exit(EX_SOFTWARE); fprintf (stderr, "%s: Could not allocate memory.\n", argv[0]);
} exit (EX_SOFTWARE);
break; }
case 'h': break;
default: case 'h':
display_usage(); default:
exit(EX_OK); display_usage ();
} exit (EX_OK);
} }
}
log_message(LOG_INFO, "Initializing " PACKAGE " ..."); log_message (LOG_INFO, "Initializing " PACKAGE " ...");
/* /*
* Make sure the HTML error pages array is NULL to begin with. * Make sure the HTML error pages array is NULL to begin with.
* (FIXME: Should have a better API for all this) * (FIXME: Should have a better API for all this)
*/ */
config.errorpages = NULL; config.errorpages = NULL;
/* /*
* Read in the settings from the config file. * Read in the settings from the config file.
*/ */
config_file = fopen(config.config_file, "r"); config_file = fopen (config.config_file, "r");
if (!config_file) { if (!config_file)
fprintf(stderr, {
"%s: Could not open configuration file \"%s\".\n", fprintf (stderr,
argv[0], config.config_file); "%s: Could not open configuration file \"%s\".\n",
exit(EX_SOFTWARE); argv[0], config.config_file);
} exit (EX_SOFTWARE);
if (config_compile() || config_parse(&config, config_file)) { }
fprintf(stderr, if (config_compile () || config_parse (&config, config_file))
"Unable to parse configuration file. Not starting.\n"); {
exit(EX_SOFTWARE); fprintf (stderr,
} "Unable to parse configuration file. Not starting.\n");
fclose(config_file); exit (EX_SOFTWARE);
}
fclose (config_file);
/* /*
* Write to a user supplied log file if it's defined. This * Write to a user supplied log file if it's defined. This
* will override using the syslog even if syslog is defined. * will override using the syslog even if syslog is defined.
*/ */
if (config.logf_name) { if (config.logf_name)
if (open_log_file(config.logf_name) < 0) { {
fprintf(stderr, if (open_log_file (config.logf_name) < 0)
"%s: Could not create log file.\n", argv[0]); {
exit(EX_SOFTWARE); fprintf (stderr, "%s: Could not create log file.\n", argv[0]);
} exit (EX_SOFTWARE);
config.syslog = FALSE; /* disable syslog */ }
} else if (config.syslog) { config.syslog = FALSE; /* disable syslog */
if (godaemon == TRUE) }
openlog("tinyproxy", LOG_PID, LOG_DAEMON); else if (config.syslog)
else {
openlog("tinyproxy", LOG_PID, LOG_USER); if (godaemon == TRUE)
} else { openlog ("tinyproxy", LOG_PID, LOG_DAEMON);
fprintf(stderr, else
"%s: Either define a logfile or enable syslog logging\n", openlog ("tinyproxy", LOG_PID, LOG_USER);
argv[0]); }
exit(EX_SOFTWARE); else
} {
fprintf (stderr,
"%s: Either define a logfile or enable syslog logging\n",
argv[0]);
exit (EX_SOFTWARE);
}
processed_config_file = TRUE; processed_config_file = TRUE;
send_stored_logs(); send_stored_logs ();
/* /*
* Set the default values if they were not set in the config file. * Set the default values if they were not set in the config file.
*/ */
if (config.port == 0) { if (config.port == 0)
fprintf(stderr, {
"%s: You MUST set a Port in the configuration file.\n", fprintf (stderr,
argv[0]); "%s: You MUST set a Port in the configuration file.\n",
exit(EX_SOFTWARE); argv[0]);
} exit (EX_SOFTWARE);
if (!config.stathost) { }
log_message(LOG_INFO, "Setting stathost to \"%s\".", if (!config.stathost)
DEFAULT_STATHOST); {
config.stathost = DEFAULT_STATHOST; log_message (LOG_INFO, "Setting stathost to \"%s\".", DEFAULT_STATHOST);
} config.stathost = DEFAULT_STATHOST;
if (!config.user) { }
log_message(LOG_WARNING, if (!config.user)
"You SHOULD set a UserName in the configuration file. Using current user instead."); {
} log_message (LOG_WARNING,
if (config.idletimeout == 0) { "You SHOULD set a UserName in the configuration file. Using current user instead.");
log_message(LOG_WARNING, }
"Invalid idle time setting. Only values greater than zero allowed; therefore setting idle timeout to %u seconds.", if (config.idletimeout == 0)
MAX_IDLE_TIME); {
config.idletimeout = MAX_IDLE_TIME; log_message (LOG_WARNING,
} "Invalid idle time setting. Only values greater than zero allowed; therefore setting idle timeout to %u seconds.",
MAX_IDLE_TIME);
config.idletimeout = MAX_IDLE_TIME;
}
init_stats(); init_stats ();
/* /*
* If ANONYMOUS is turned on, make sure that Content-Length is * If ANONYMOUS is turned on, make sure that Content-Length is
* in the list of allowed headers, since it is required in a * in the list of allowed headers, since it is required in a
* HTTP/1.0 request. Also add the Content-Type header since it goes * HTTP/1.0 request. Also add the Content-Type header since it goes
* hand in hand with Content-Length. * hand in hand with Content-Length.
* - rjkaes * - rjkaes
*/ */
if (is_anonymous_enabled()) { if (is_anonymous_enabled ())
anonymous_insert("Content-Length"); {
anonymous_insert("Content-Type"); anonymous_insert ("Content-Length");
} anonymous_insert ("Content-Type");
}
if (godaemon == TRUE) if (godaemon == TRUE)
makedaemon(); makedaemon ();
if (config.pidpath) { if (config.pidpath)
if (pidfile_create(config.pidpath) < 0) { {
fprintf(stderr, "%s: Could not create PID file.\n", if (pidfile_create (config.pidpath) < 0)
argv[0]); {
exit(EX_OSERR); fprintf (stderr, "%s: Could not create PID file.\n", argv[0]);
} exit (EX_OSERR);
} }
}
if (set_signal_handler(SIGPIPE, SIG_IGN) == SIG_ERR) { if (set_signal_handler (SIGPIPE, SIG_IGN) == SIG_ERR)
fprintf(stderr, "%s: Could not set the \"SIGPIPE\" signal.\n", {
argv[0]); fprintf (stderr, "%s: Could not set the \"SIGPIPE\" signal.\n",
exit(EX_OSERR); argv[0]);
} 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_sock(config.port) < 0) { if (child_listening_sock (config.port) < 0)
fprintf(stderr, "%s: Could not create listening socket.\n", {
argv[0]); fprintf (stderr, "%s: Could not create listening socket.\n", argv[0]);
exit(EX_OSERR); exit (EX_OSERR);
} }
/* /*
* Switch to a different user. * Switch to a different user.
*/ */
if (geteuid() == 0) { if (geteuid () == 0)
if (config.group && strlen(config.group) > 0) { {
int gid = get_id(config.group); if (config.group && strlen (config.group) > 0)
if (gid < 0) { {
thisgroup = getgrnam(config.group); int gid = get_id (config.group);
if (!thisgroup) { if (gid < 0)
fprintf(stderr, {
"%s: Unable to find " thisgroup = getgrnam (config.group);
"group \"%s\".\n", if (!thisgroup)
argv[0], config.group); {
exit(EX_NOUSER); fprintf (stderr,
} "%s: Unable to find "
gid = thisgroup->gr_gid; "group \"%s\".\n", argv[0], config.group);
} exit (EX_NOUSER);
if (setgid(gid) < 0) { }
fprintf(stderr, gid = thisgroup->gr_gid;
"%s: Unable to change to " }
"group \"%s\".\n", if (setgid (gid) < 0)
argv[0], config.group); {
exit(EX_CANTCREAT); fprintf (stderr,
} "%s: Unable to change to "
log_message(LOG_INFO, "Now running as group \"%s\".", "group \"%s\".\n", argv[0], config.group);
config.group); exit (EX_CANTCREAT);
} }
if (config.user && strlen(config.user) > 0) { log_message (LOG_INFO, "Now running as group \"%s\".",
int uid = get_id(config.user); config.group);
if (uid < 0) { }
thisuser = getpwnam(config.user); if (config.user && strlen (config.user) > 0)
if (!thisuser) { {
fprintf(stderr, int uid = get_id (config.user);
"%s: Unable to find " if (uid < 0)
"user \"%s\".", {
argv[0], config.user); thisuser = getpwnam (config.user);
exit(EX_NOUSER); if (!thisuser)
} {
uid = thisuser->pw_uid; fprintf (stderr,
} "%s: Unable to find "
if (setuid(uid) < 0) { "user \"%s\".", argv[0], config.user);
fprintf(stderr, exit (EX_NOUSER);
"%s: Unable to change to user \"%s\".", }
argv[0], config.user); uid = thisuser->pw_uid;
exit(EX_CANTCREAT); }
} if (setuid (uid) < 0)
log_message(LOG_INFO, "Now running as user \"%s\".", {
config.user); fprintf (stderr,
} "%s: Unable to change to user \"%s\".",
} else { argv[0], config.user);
log_message(LOG_WARNING, exit (EX_CANTCREAT);
"Not running as root, so not changing UID/GID."); }
} log_message (LOG_INFO, "Now running as user \"%s\".", config.user);
}
}
else
{
log_message (LOG_WARNING,
"Not running as root, so not changing UID/GID.");
}
if (child_pool_create() < 0) { if (child_pool_create () < 0)
fprintf(stderr, "%s: Could not create the pool of children.", {
argv[0]); fprintf (stderr, "%s: Could not create the pool of children.", argv[0]);
exit(EX_SOFTWARE); 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.");
if (set_signal_handler(SIGCHLD, takesig) == SIG_ERR) { if (set_signal_handler (SIGCHLD, takesig) == SIG_ERR)
fprintf(stderr, "%s: Could not set the \"SIGCHLD\" signal.\n", {
argv[0]); fprintf (stderr, "%s: Could not set the \"SIGCHLD\" signal.\n",
exit(EX_OSERR); argv[0]);
} exit (EX_OSERR);
if (set_signal_handler(SIGTERM, takesig) == SIG_ERR) { }
fprintf(stderr, "%s: Could not set the \"SIGTERM\" signal.\n", if (set_signal_handler (SIGTERM, takesig) == SIG_ERR)
argv[0]); {
exit(EX_OSERR); fprintf (stderr, "%s: Could not set the \"SIGTERM\" signal.\n",
} argv[0]);
if (set_signal_handler(SIGHUP, takesig) == SIG_ERR) { exit (EX_OSERR);
fprintf(stderr, "%s: Could not set the \"SIGHUP\" signal.\n", }
argv[0]); if (set_signal_handler (SIGHUP, takesig) == SIG_ERR)
exit(EX_OSERR); {
} fprintf (stderr, "%s: Could not set the \"SIGHUP\" signal.\n", argv[0]);
exit (EX_OSERR);
}
/* /*
* Start the main loop. * Start the main loop.
*/ */
log_message(LOG_INFO, "Starting main loop. Accepting connections."); log_message (LOG_INFO, "Starting main loop. Accepting connections.");
child_main_loop(); child_main_loop ();
log_message(LOG_INFO, "Shutting down."); log_message (LOG_INFO, "Shutting down.");
child_kill_children(); child_kill_children ();
child_close_sock(); child_close_sock ();
/* /*
* Remove the PID file. * Remove the PID file.
*/ */
if (unlink(config.pidpath) < 0) { if (unlink (config.pidpath) < 0)
log_message(LOG_WARNING, {
"Could not remove PID file \"%s\": %s.", log_message (LOG_WARNING,
config.pidpath, strerror(errno)); "Could not remove PID file \"%s\": %s.",
} config.pidpath, strerror (errno));
}
#ifdef FILTER_ENABLE #ifdef FILTER_ENABLE
if (config.filter) if (config.filter)
filter_destroy(); filter_destroy ();
#endif /* FILTER_ENABLE */ #endif /* FILTER_ENABLE */
if (config.syslog) if (config.syslog)
closelog(); closelog ();
else else
close_log_file(); close_log_file ();
exit(EX_OK); exit (EX_OK);
} }

View File

@ -26,82 +26,84 @@
#include "hashmap.h" #include "hashmap.h"
/* Global variables for the main controls of the program */ /* Global variables for the main controls of the program */
#define MAXBUFFSIZE ((size_t)(1024 * 96)) /* Max size of buffer */ #define MAXBUFFSIZE ((size_t)(1024 * 96)) /* Max size of buffer */
#define MAX_IDLE_TIME (60 * 10) /* 10 minutes of no activity */ #define MAX_IDLE_TIME (60 * 10) /* 10 minutes of no activity */
/* /*
* Even if upstream support is not compiled into tinyproxy, this * Even if upstream support is not compiled into tinyproxy, this
* structure still needs to be defined. * structure still needs to be defined.
*/ */
struct upstream { struct upstream
struct upstream *next; {
char *domain; /* optional */ struct upstream *next;
char *host; char *domain; /* optional */
int port; char *host;
in_addr_t ip, mask; int port;
in_addr_t ip, mask;
}; };
/* /*
* Hold all the configuration time information. * Hold all the configuration time information.
*/ */
struct config_s { struct config_s
char *logf_name; {
char *config_file; char *logf_name;
unsigned int syslog; /* boolean */ char *config_file;
int port; unsigned int syslog; /* boolean */
char *stathost; int port;
unsigned int quit; /* boolean */ char *stathost;
char *user; unsigned int quit; /* boolean */
char *group; char *user;
char *ipAddr; char *group;
char *ipAddr;
#ifdef FILTER_ENABLE #ifdef FILTER_ENABLE
char *filter; char *filter;
unsigned int filter_url; /* boolean */ unsigned int filter_url; /* boolean */
unsigned int filter_extended; /* boolean */ unsigned int filter_extended; /* boolean */
unsigned int filter_casesensitive; /* boolean */ unsigned int filter_casesensitive; /* boolean */
#endif /* FILTER_ENABLE */ #endif /* FILTER_ENABLE */
#ifdef XTINYPROXY_ENABLE #ifdef XTINYPROXY_ENABLE
char *my_domain; char *my_domain;
#endif #endif
#ifdef REVERSE_SUPPORT #ifdef REVERSE_SUPPORT
struct reversepath *reversepath_list; struct reversepath *reversepath_list;
unsigned int reverseonly; /* boolean */ unsigned int reverseonly; /* boolean */
unsigned int reversemagic; /* boolean */ unsigned int reversemagic; /* boolean */
char *reversebaseurl; char *reversebaseurl;
#endif #endif
#ifdef UPSTREAM_SUPPORT #ifdef UPSTREAM_SUPPORT
struct upstream *upstream_list; struct upstream *upstream_list;
#endif /* UPSTREAM_SUPPORT */ #endif /* UPSTREAM_SUPPORT */
char *pidpath; char *pidpath;
unsigned int idletimeout; unsigned int idletimeout;
char *bind_address; char *bind_address;
unsigned int bindsame; unsigned int bindsame;
/* /*
* The configured name to use in the HTTP "Via" header field. * The configured name to use in the HTTP "Via" header field.
*/ */
char *via_proxy_name; char *via_proxy_name;
/* /*
* Error page support. Map error numbers to file paths. * Error page support. Map error numbers to file paths.
*/ */
hashmap_t errorpages; hashmap_t errorpages;
/* /*
* Error page to be displayed if appropriate page cannot be located * Error page to be displayed if appropriate page cannot be located
* in the errorpages structure. * in the errorpages structure.
*/ */
char *errorpage_undef; char *errorpage_undef;
/* /*
* The HTML statistics page. * The HTML statistics page.
*/ */
char *statpage; char *statpage;
}; };
/* Global Structures used in the program */ /* Global Structures used in the program */
extern struct config_s config; extern struct config_s config;
extern unsigned int received_sighup; /* boolean */ extern unsigned int received_sighup; /* boolean */
extern unsigned int processed_config_file; /* boolean */ extern unsigned int processed_config_file; /* boolean */
#endif #endif

View File

@ -36,86 +36,86 @@
* Build a URL from parts. * Build a URL from parts.
*/ */
static int static int
build_url(char **url, const char *host, int port, const char *path) build_url (char **url, const char *host, int port, const char *path)
{ {
int len; int len;
assert(url != NULL); assert (url != NULL);
assert(host != NULL); assert (host != NULL);
assert(port > 0 && port < 32768); assert (port > 0 && port < 32768);
assert(path != NULL); assert (path != NULL);
len = strlen(host) + strlen(path) + 14; len = strlen (host) + strlen (path) + 14;
*url = safemalloc(len); *url = safemalloc (len);
if (*url == NULL) if (*url == NULL)
return -1; return -1;
return snprintf(*url, len, "http://%s:%d%s", host, port, path); return snprintf (*url, len, "http://%s:%d%s", host, port, path);
} }
int int
do_transparent_proxy(struct conn_s *connptr, hashmap_t hashofheaders, do_transparent_proxy (struct conn_s *connptr, hashmap_t hashofheaders,
struct request_s *request, struct config_s *conf, char *url) struct request_s *request, struct config_s *conf,
char *url)
{ {
socklen_t length; socklen_t length;
char *data; char *data;
length =
hashmap_entry_by_key(hashofheaders, "host", (void **)&data);
if (length <= 0) {
struct sockaddr_in dest_addr;
if (getsockname
(connptr->client_fd, (struct sockaddr *)&dest_addr,
&length) < 0) {
log_message(LOG_ERR,
"process_request: cannot get destination IP for %d",
connptr->client_fd);
indicate_http_error(connptr, 400, "Bad Request",
"detail",
"Unknown destination",
"url", url, NULL);
return 0;
}
request->host = safemalloc(17);
strcpy(request->host, inet_ntoa(dest_addr.sin_addr));
request->port = ntohs(dest_addr.sin_port);
request->path = safemalloc(strlen(url) + 1);
strcpy(request->path, url);
safefree(url);
build_url(&url, request->host, request->port,
request->path);
log_message(LOG_INFO,
"process_request: trans IP %s %s for %d",
request->method, url, connptr->client_fd);
} else {
request->host = safemalloc(length + 1);
if (sscanf
(data, "%[^:]:%hu", request->host,
&request->port) != 2) {
strcpy(request->host, data);
request->port = HTTP_PORT;
}
request->path = safemalloc(strlen(url) + 1);
strcpy(request->path, url);
safefree(url);
build_url(&url, request->host, request->port,
request->path);
log_message(LOG_INFO,
"process_request: trans Host %s %s for %d",
request->method, url, connptr->client_fd);
}
if (conf->ipAddr && strcmp(request->host, conf->ipAddr) == 0) {
log_message(LOG_ERR,
"process_request: destination IP is localhost %d",
connptr->client_fd);
indicate_http_error(connptr, 400, "Bad Request",
"detail",
"You tried to connect to the machine the proxy is running on",
"url", url, NULL);
return 0;
}
return 1; length = hashmap_entry_by_key (hashofheaders, "host", (void **) &data);
if (length <= 0)
{
struct sockaddr_in dest_addr;
if (getsockname
(connptr->client_fd, (struct sockaddr *) &dest_addr, &length) < 0)
{
log_message (LOG_ERR,
"process_request: cannot get destination IP for %d",
connptr->client_fd);
indicate_http_error (connptr, 400, "Bad Request",
"detail",
"Unknown destination", "url", url, NULL);
return 0;
}
request->host = safemalloc (17);
strcpy (request->host, inet_ntoa (dest_addr.sin_addr));
request->port = ntohs (dest_addr.sin_port);
request->path = safemalloc (strlen (url) + 1);
strcpy (request->path, url);
safefree (url);
build_url (&url, request->host, request->port, request->path);
log_message (LOG_INFO,
"process_request: trans IP %s %s for %d",
request->method, url, connptr->client_fd);
}
else
{
request->host = safemalloc (length + 1);
if (sscanf (data, "%[^:]:%hu", request->host, &request->port) != 2)
{
strcpy (request->host, data);
request->port = HTTP_PORT;
}
request->path = safemalloc (strlen (url) + 1);
strcpy (request->path, url);
safefree (url);
build_url (&url, request->host, request->port, request->path);
log_message (LOG_INFO,
"process_request: trans Host %s %s for %d",
request->method, url, connptr->client_fd);
}
if (conf->ipAddr && strcmp (request->host, conf->ipAddr) == 0)
{
log_message (LOG_ERR,
"process_request: destination IP is localhost %d",
connptr->client_fd);
indicate_http_error (connptr, 400, "Bad Request",
"detail",
"You tried to connect to the machine the proxy is running on",
"url", url, NULL);
return 0;
}
return 1;
} }

View File

@ -29,9 +29,10 @@
#include "hashmap.h" #include "hashmap.h"
#include "reqs.h" #include "reqs.h"
extern int do_transparent_proxy(struct conn_s *connptr, extern int do_transparent_proxy (struct conn_s *connptr,
hashmap_t hashofheaders, struct request_s *request, hashmap_t hashofheaders,
struct config_s *config, char *url); struct request_s *request,
struct config_s *config, char *url);
#endif #endif

View File

@ -34,175 +34,183 @@
* Build the data for a complete HTTP & HTML message for the client. * Build the data for a complete HTTP & HTML message for the client.
*/ */
int int
send_http_message(struct conn_s *connptr, int http_code, send_http_message (struct conn_s *connptr, int http_code,
const char *error_title, const char *message) const char *error_title, const char *message)
{ {
static char *headers[] = { static char *headers[] = {
"Server: " PACKAGE "/" VERSION, "Server: " PACKAGE "/" VERSION,
"Content-type: text/html", "Content-type: text/html",
"Connection: close" "Connection: close"
}; };
http_message_t msg; http_message_t msg;
msg = http_message_create(http_code, error_title); msg = http_message_create (http_code, error_title);
if (msg == NULL) if (msg == NULL)
return -1; return -1;
http_message_add_headers(msg, headers, 3); http_message_add_headers (msg, headers, 3);
http_message_set_body(msg, message, strlen(message)); http_message_set_body (msg, message, strlen (message));
http_message_send(msg, connptr->client_fd); http_message_send (msg, connptr->client_fd);
http_message_destroy(msg); http_message_destroy (msg);
return 0; return 0;
} }
/* /*
* Safely creates filename and returns the low-level file descriptor. * Safely creates filename and returns the low-level file descriptor.
*/ */
int int
create_file_safely(const char *filename, unsigned int truncate_file) create_file_safely (const char *filename, unsigned int truncate_file)
{ {
struct stat lstatinfo; struct stat lstatinfo;
int fildes; int fildes;
/* /*
* lstat() the file. If it doesn't exist, create it with O_EXCL. * lstat() the file. If it doesn't exist, create it with O_EXCL.
* If it does exist, open it for writing and perform the fstat() * If it does exist, open it for writing and perform the fstat()
* check. * check.
*/ */
if (lstat(filename, &lstatinfo) < 0) { if (lstat (filename, &lstatinfo) < 0)
/* {
* If lstat() failed for any reason other than "file not /*
* existing", exit. * If lstat() failed for any reason other than "file not
*/ * existing", exit.
if (errno != ENOENT) { */
fprintf(stderr, if (errno != ENOENT)
"%s: Error checking file %s: %s\n", {
PACKAGE, filename, strerror(errno)); fprintf (stderr,
return -EACCES; "%s: Error checking file %s: %s\n",
} PACKAGE, filename, strerror (errno));
return -EACCES;
}
/* /*
* The file doesn't exist, so create it with O_EXCL to make * The file doesn't exist, so create it with O_EXCL to make
* sure an attacker can't slip in a file between the lstat() * sure an attacker can't slip in a file between the lstat()
* and open() * and open()
*/ */
if ((fildes = if ((fildes = open (filename, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0)
open(filename, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0) { {
fprintf(stderr, fprintf (stderr,
"%s: Could not create file %s: %s\n", "%s: Could not create file %s: %s\n",
PACKAGE, filename, strerror(errno)); PACKAGE, filename, strerror (errno));
return fildes; return fildes;
} }
} else { }
struct stat fstatinfo; else
int flags; {
struct stat fstatinfo;
int flags;
flags = O_RDWR; flags = O_RDWR;
if (!truncate_file) if (!truncate_file)
flags |= O_APPEND; flags |= O_APPEND;
/* /*
* Open an existing file. * Open an existing file.
*/ */
if ((fildes = open(filename, flags)) < 0) { if ((fildes = open (filename, flags)) < 0)
fprintf(stderr, {
"%s: Could not open file %s: %s\n", fprintf (stderr,
PACKAGE, filename, strerror(errno)); "%s: Could not open file %s: %s\n",
return fildes; PACKAGE, filename, strerror (errno));
} return fildes;
}
/* /*
* fstat() the opened file and check that the file mode bits, * fstat() the opened file and check that the file mode bits,
* inode, and device match. * inode, and device match.
*/ */
if (fstat(fildes, &fstatinfo) < 0 if (fstat (fildes, &fstatinfo) < 0
|| lstatinfo.st_mode != fstatinfo.st_mode || lstatinfo.st_mode != fstatinfo.st_mode
|| lstatinfo.st_ino != fstatinfo.st_ino || lstatinfo.st_ino != fstatinfo.st_ino
|| lstatinfo.st_dev != fstatinfo.st_dev) { || lstatinfo.st_dev != fstatinfo.st_dev)
fprintf(stderr, {
"%s: The file %s has been changed before it could be opened\n", fprintf (stderr,
PACKAGE, filename); "%s: The file %s has been changed before it could be opened\n",
close(fildes); PACKAGE, filename);
return -EIO; close (fildes);
} return -EIO;
}
/* /*
* If the above check was passed, we know that the lstat() * If the above check was passed, we know that the lstat()
* and fstat() were done on the same file. Now we check that * and fstat() were done on the same file. Now we check that
* there's only one link, and that it's a normal file (this * there's only one link, and that it's a normal file (this
* isn't strictly necessary because the fstat() vs lstat() * isn't strictly necessary because the fstat() vs lstat()
* st_mode check would also find this) * st_mode check would also find this)
*/ */
if (fstatinfo.st_nlink > 1 || !S_ISREG(lstatinfo.st_mode)) { if (fstatinfo.st_nlink > 1 || !S_ISREG (lstatinfo.st_mode))
fprintf(stderr, {
"%s: The file %s has too many links, or is not a regular file: %s\n", fprintf (stderr,
PACKAGE, filename, strerror(errno)); "%s: The file %s has too many links, or is not a regular file: %s\n",
close(fildes); PACKAGE, filename, strerror (errno));
return -EMLINK; close (fildes);
} return -EMLINK;
}
/* /*
* Just return the file descriptor if we _don't_ want the file * Just return the file descriptor if we _don't_ want the file
* truncated. * truncated.
*/ */
if (!truncate_file) if (!truncate_file)
return fildes; return fildes;
/* /*
* On systems which don't support ftruncate() the best we can * On systems which don't support ftruncate() the best we can
* do is to close the file and reopen it in create mode, which * do is to close the file and reopen it in create mode, which
* unfortunately leads to a race condition, however "systems * unfortunately leads to a race condition, however "systems
* which don't support ftruncate()" is pretty much SCO only, * which don't support ftruncate()" is pretty much SCO only,
* and if you're using that you deserve what you get. * and if you're using that you deserve what you get.
* ("Little sympathy has been extended") * ("Little sympathy has been extended")
*/ */
#ifdef HAVE_FTRUNCATE #ifdef HAVE_FTRUNCATE
ftruncate(fildes, 0); ftruncate (fildes, 0);
#else #else
close(fildes); close (fildes);
if ((fildes = if ((fildes = open (filename, O_RDWR | O_CREAT | O_TRUNC, 0600)) < 0)
open(filename, O_RDWR | O_CREAT | O_TRUNC, 0600)) < 0) { {
fprintf(stderr, fprintf (stderr,
"%s: Could not open file %s: %s.", "%s: Could not open file %s: %s.",
PACKAGE, filename, strerror(errno)); PACKAGE, filename, strerror (errno));
return fildes; return fildes;
} }
#endif /* HAVE_FTRUNCATE */ #endif /* HAVE_FTRUNCATE */
} }
return fildes; return fildes;
} }
/* /*
* Write the PID of the program to the specified file. * Write the PID of the program to the specified file.
*/ */
int int
pidfile_create(const char *filename) pidfile_create (const char *filename)
{ {
int fildes; int fildes;
FILE *fd; FILE *fd;
/* /*
* Create a new file * Create a new file
*/ */
if ((fildes = create_file_safely(filename, TRUE)) < 0) if ((fildes = create_file_safely (filename, TRUE)) < 0)
return fildes; return fildes;
/* /*
* Open a stdio file over the low-level one. * Open a stdio file over the low-level one.
*/ */
if ((fd = fdopen(fildes, "w")) == NULL) { if ((fd = fdopen (fildes, "w")) == NULL)
fprintf(stderr, {
"%s: Could not write PID file %s: %s.", fprintf (stderr,
PACKAGE, filename, strerror(errno)); "%s: Could not write PID file %s: %s.",
close(fildes); PACKAGE, filename, strerror (errno));
unlink(filename); close (fildes);
return -EIO; unlink (filename);
} return -EIO;
}
fprintf(fd, "%ld\n", (long)getpid()); fprintf (fd, "%ld\n", (long) getpid ());
fclose(fd); fclose (fd);
return 0; return 0;
} }

View File

@ -27,10 +27,11 @@
*/ */
struct conn_s; struct conn_s;
extern int send_http_message(struct conn_s *connptr, int http_code, extern int send_http_message (struct conn_s *connptr, int http_code,
const char *error_title, const char *message); const char *error_title, const char *message);
extern int pidfile_create(const char *path); extern int pidfile_create (const char *path);
extern int create_file_safely(const char *filename, unsigned int truncate_file); extern int create_file_safely (const char *filename,
unsigned int truncate_file);
#endif #endif

View File

@ -33,17 +33,19 @@
* vector_s stores a pointer to the first vector (vector[0]) and a * vector_s stores a pointer to the first vector (vector[0]) and a
* count of the number of entries (or how long the vector is.) * count of the number of entries (or how long the vector is.)
*/ */
struct vectorentry_s { struct vectorentry_s
void *data; {
size_t len; void *data;
size_t len;
struct vectorentry_s *next; struct vectorentry_s *next;
}; };
struct vector_s { struct vector_s
size_t num_entries; {
struct vectorentry_s *head; size_t num_entries;
struct vectorentry_s *tail; struct vectorentry_s *head;
struct vectorentry_s *tail;
}; };
/* /*
@ -54,18 +56,18 @@ struct vector_s {
* vector. * vector.
*/ */
vector_t vector_t
vector_create(void) vector_create (void)
{ {
vector_t vector; vector_t vector;
vector = safemalloc(sizeof(struct vector_s)); vector = safemalloc (sizeof (struct vector_s));
if (!vector) if (!vector)
return NULL; return NULL;
vector->num_entries = 0; vector->num_entries = 0;
vector->head = vector->tail = NULL; vector->head = vector->tail = NULL;
return vector; return vector;
} }
/* /*
@ -75,25 +77,26 @@ vector_create(void)
* negative if a NULL vector is supplied * negative if a NULL vector is supplied
*/ */
int int
vector_delete(vector_t vector) vector_delete (vector_t vector)
{ {
struct vectorentry_s *ptr, *next; struct vectorentry_s *ptr, *next;
if (!vector) if (!vector)
return -EINVAL; return -EINVAL;
ptr = vector->head; ptr = vector->head;
while (ptr) { while (ptr)
next = ptr->next; {
safefree(ptr->data); next = ptr->next;
safefree(ptr); safefree (ptr->data);
safefree (ptr);
ptr = next; ptr = next;
} }
safefree(vector); safefree (vector);
return 0; return 0;
} }
/* /*
@ -110,44 +113,48 @@ vector_delete(vector_t vector)
#define INSERT_APPEND 1 #define INSERT_APPEND 1
static int static int
vector_insert(vector_t vector, void *data, ssize_t len, int pos) vector_insert (vector_t vector, void *data, ssize_t len, int pos)
{ {
struct vectorentry_s *entry; struct vectorentry_s *entry;
if (!vector || !data || len <= 0 || if (!vector || !data || len <= 0 ||
(pos != INSERT_PREPEND && pos != INSERT_APPEND)) (pos != INSERT_PREPEND && pos != INSERT_APPEND))
return -EINVAL; return -EINVAL;
entry = safemalloc(sizeof(struct vectorentry_s)); entry = safemalloc (sizeof (struct vectorentry_s));
if (!entry) if (!entry)
return -ENOMEM; return -ENOMEM;
entry->data = safemalloc(len); entry->data = safemalloc (len);
if (!entry->data) { if (!entry->data)
safefree(entry); {
return -ENOMEM; safefree (entry);
} return -ENOMEM;
}
memcpy(entry->data, data, len); memcpy (entry->data, data, len);
entry->len = len; entry->len = len;
entry->next = NULL; entry->next = NULL;
/* If there is no head or tail, create them */ /* If there is no head or tail, create them */
if (!vector->head && !vector->tail) if (!vector->head && !vector->tail)
vector->head = vector->tail = entry; vector->head = vector->tail = entry;
else if (pos == 0) { else if (pos == 0)
/* prepend the entry */ {
entry->next = vector->head; /* prepend the entry */
vector->head = entry; entry->next = vector->head;
} else { vector->head = entry;
/* append the entry */ }
vector->tail->next = entry; else
vector->tail = entry; {
} /* append the entry */
vector->tail->next = entry;
vector->tail = entry;
}
vector->num_entries++; vector->num_entries++;
return 0; return 0;
} }
/* /*
@ -156,15 +163,15 @@ vector_insert(vector_t vector, void *data, ssize_t len, int pos)
* arguments. * arguments.
*/ */
int int
vector_append(vector_t vector, void *data, ssize_t len) vector_append (vector_t vector, void *data, ssize_t len)
{ {
return vector_insert(vector, data, len, INSERT_APPEND); return vector_insert (vector, data, len, INSERT_APPEND);
} }
int int
vector_prepend(vector_t vector, void *data, ssize_t len) vector_prepend (vector_t vector, void *data, ssize_t len)
{ {
return vector_insert(vector, data, len, INSERT_PREPEND); return vector_insert (vector, data, len, INSERT_PREPEND);
} }
/* /*
@ -175,26 +182,27 @@ vector_prepend(vector_t vector, void *data, ssize_t len)
* length of data if position is valid * length of data if position is valid
*/ */
void * void *
vector_getentry(vector_t vector, size_t pos, size_t * size) vector_getentry (vector_t vector, size_t pos, size_t * size)
{ {
struct vectorentry_s *ptr; struct vectorentry_s *ptr;
size_t loc; size_t loc;
if (!vector || pos >= vector->num_entries) if (!vector || pos >= vector->num_entries)
return NULL; return NULL;
loc = 0; loc = 0;
ptr = vector->head; ptr = vector->head;
while (loc != pos) { while (loc != pos)
ptr = ptr->next; {
loc++; ptr = ptr->next;
} loc++;
}
if (size) if (size)
*size = ptr->len; *size = ptr->len;
return ptr->data; return ptr->data;
} }
/* /*
@ -204,10 +212,10 @@ vector_getentry(vector_t vector, size_t pos, size_t * size)
* positive length of vector otherwise * positive length of vector otherwise
*/ */
ssize_t ssize_t
vector_length(vector_t vector) vector_length (vector_t vector)
{ {
if (!vector) if (!vector)
return -EINVAL; return -EINVAL;
return vector->num_entries; return vector->num_entries;
} }

View File

@ -23,7 +23,8 @@
/* Allow the use in C++ code. */ /* Allow the use in C++ code. */
#if defined(__cplusplus) #if defined(__cplusplus)
extern "C" { extern "C"
{
#endif #endif
/* /*
@ -31,14 +32,14 @@ extern "C" {
* vector. Sure, it's a pointer, but the struct is hidden in the C file. * vector. Sure, it's a pointer, but the struct is hidden in the C file.
* So, just use the vector_t like it's a cookie. :) * So, just use the vector_t like it's a cookie. :)
*/ */
typedef struct vector_s *vector_t; typedef struct vector_s *vector_t;
/* /*
* vector_create() takes no arguments. * vector_create() takes no arguments.
* vector_delete() is self explanatory. * vector_delete() is self explanatory.
*/ */
extern vector_t vector_create(void); extern vector_t vector_create (void);
extern int vector_delete(vector_t vector); extern int vector_delete (vector_t vector);
/* /*
* When you insert a piece of data into the vector, the data will be * When you insert a piece of data into the vector, the data will be
@ -48,8 +49,8 @@ extern "C" {
* Returns: negative on error * Returns: negative on error
* 0 upon successful insert. * 0 upon successful insert.
*/ */
extern int vector_append(vector_t vector, void *data, ssize_t len); extern int vector_append (vector_t vector, void *data, ssize_t len);
extern int vector_prepend(vector_t vector, void *data, ssize_t len); extern int vector_prepend (vector_t vector, void *data, ssize_t len);
/* /*
* A pointer to the data at position "pos" (zero based) is returned and the * A pointer to the data at position "pos" (zero based) is returned and the
@ -67,8 +68,7 @@ extern "C" {
* Returns: NULL on error * Returns: NULL on error
* valid pointer to data * valid pointer to data
*/ */
extern void *vector_getentry(vector_t vector, size_t pos, extern void *vector_getentry (vector_t vector, size_t pos, size_t * size);
size_t * size);
/* /*
* Returns the number of enteries (or the length) of the vector. * Returns the number of enteries (or the length) of the vector.
@ -76,9 +76,9 @@ extern "C" {
* Returns: negative if vector is not valid * Returns: negative if vector is not valid
* positive length of vector otherwise * positive length of vector otherwise
*/ */
extern ssize_t vector_length(vector_t vector); extern ssize_t vector_length (vector_t vector);
#if defined(__cplusplus) #if defined(__cplusplus)
} }
#endif /* C++ */ #endif /* C++ */
#endif /* _VECTOR_H */ #endif /* _VECTOR_H */