diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/acl.c | 503 | ||||
-rw-r--r-- | src/acl.h | 9 | ||||
-rw-r--r-- | src/anonymous.c | 42 | ||||
-rw-r--r-- | src/anonymous.h | 6 | ||||
-rw-r--r-- | src/buffer.c | 391 | ||||
-rw-r--r-- | src/buffer.h | 16 | ||||
-rw-r--r-- | src/child.c | 611 | ||||
-rw-r--r-- | src/child.h | 25 | ||||
-rw-r--r-- | src/common.h | 10 | ||||
-rw-r--r-- | src/conffile.c | 788 | ||||
-rw-r--r-- | src/conffile.h | 4 | ||||
-rw-r--r-- | src/conns.c | 168 | ||||
-rw-r--r-- | src/conns.h | 121 | ||||
-rw-r--r-- | src/daemon.c | 61 | ||||
-rw-r--r-- | src/daemon.h | 4 | ||||
-rw-r--r-- | src/filter.c | 302 | ||||
-rw-r--r-- | src/filter.h | 17 | ||||
-rw-r--r-- | src/hashmap.c | 594 | ||||
-rw-r--r-- | src/hashmap.h | 37 | ||||
-rw-r--r-- | src/heap.c | 135 | ||||
-rw-r--r-- | src/heap.h | 22 | ||||
-rw-r--r-- | src/html-error.c | 359 | ||||
-rw-r--r-- | src/html-error.h | 19 | ||||
-rw-r--r-- | src/http-message.c | 344 | ||||
-rw-r--r-- | src/http-message.h | 24 | ||||
-rw-r--r-- | src/log.c | 210 | ||||
-rw-r--r-- | src/log.h | 14 | ||||
-rw-r--r-- | src/network.c | 470 | ||||
-rw-r--r-- | src/network.h | 12 | ||||
-rw-r--r-- | src/reqs.c | 2745 | ||||
-rw-r--r-- | src/reqs.h | 19 | ||||
-rw-r--r-- | src/reverse-proxy.c | 216 | ||||
-rw-r--r-- | src/reverse-proxy.h | 17 | ||||
-rw-r--r-- | src/sock.c | 320 | ||||
-rw-r--r-- | src/sock.h | 12 | ||||
-rw-r--r-- | src/stats.c | 195 | ||||
-rw-r--r-- | src/stats.h | 19 | ||||
-rw-r--r-- | src/text.c | 82 | ||||
-rw-r--r-- | src/text.h | 10 | ||||
-rw-r--r-- | src/tinyproxy.c | 666 | ||||
-rw-r--r-- | src/tinyproxy.h | 108 | ||||
-rw-r--r-- | src/transparent-proxy.c | 144 | ||||
-rw-r--r-- | src/transparent-proxy.h | 7 | ||||
-rw-r--r-- | src/utils.c | 308 | ||||
-rw-r--r-- | src/utils.h | 9 | ||||
-rw-r--r-- | src/vector.c | 184 | ||||
-rw-r--r-- | src/vector.h | 22 |
47 files changed, 5372 insertions, 5029 deletions
@@ -33,23 +33,27 @@ /* Define how long an IPv6 address is in bytes (128 bits, 16 bytes) */ #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 * whether it's an ALLOW or DENY entry, and also whether it's a string * entry (like a domain name) or an IP entry. */ -struct acl_s { - acl_access_t access; - enum acl_type type; - union { - char *string; - struct { - unsigned char octet[IPV6_LEN]; - unsigned char mask[IPV6_LEN]; - } ip; - } address; +struct acl_s +{ + acl_access_t access; + enum acl_type type; + union + { + char *string; + struct + { + 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 -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; - long int mask; - char *endptr; - - errno = 0; /* to distinguish success/failure after call */ - mask = strtol(bitmask_string, &endptr, 10); - - /* check for various conversion errors */ - if ((errno == ERANGE && (mask == LONG_MIN || mask == LONG_MAX)) - || (errno != 0 && mask == 0) - || (endptr == bitmask_string)) - return -1; - - /* valid range for a bit mask */ - if (mask < 0 || mask > (8 * len)) - return -1; - - /* we have a valid range to fill in the array */ - for (i = 0; i != len; ++i) { - if (mask >= 8) { - array[i] = 0xff; - mask -= 8; - } - else if (mask > 0) { - array[i] = (unsigned char)(0xff << (8 - mask)); - mask = 0; - } - else { - array[i] = 0; - } - } - - return 0; + unsigned int i; + long int mask; + char *endptr; + + errno = 0; /* to distinguish success/failure after call */ + mask = strtol (bitmask_string, &endptr, 10); + + /* check for various conversion errors */ + if ((errno == ERANGE && (mask == LONG_MIN || mask == LONG_MAX)) + || (errno != 0 && mask == 0) || (endptr == bitmask_string)) + return -1; + + /* valid range for a bit mask */ + if (mask < 0 || mask > (8 * len)) + return -1; + + /* we have a valid range to fill in the array */ + for (i = 0; i != len; ++i) + { + if (mask >= 8) + { + array[i] = 0xff; + mask -= 8; + } + else if (mask > 0) + { + array[i] = (unsigned char) (0xff << (8 - mask)); + mask = 0; + } + else + { + array[i] = 0; + } + } + + return 0; } @@ -115,74 +123,82 @@ fill_netmask_array(char *bitmask_string, unsigned char array[], unsigned int len * 0 otherwise. */ int -insert_acl(char *location, acl_access_t access_type) +insert_acl (char *location, acl_access_t access_type) { - struct acl_s acl; - int ret; - char *p, ip_dst[IPV6_LEN]; - - assert(location != NULL); - - /* - * If the access list has not been set up, create it. - */ - if (!access_list) { - access_list = vector_create(); - if (!access_list) { - log_message(LOG_ERR, - "Unable to allocate memory for access list"); - return -1; - } - } - - /* - * Start populating the access control structure. - */ - memset(&acl, 0, sizeof(struct acl_s)); - acl.access = access_type; - - /* - * Check for a valid IP address (the simplest case) first. - */ - if (full_inet_pton(location, ip_dst) > 0) { - acl.type = ACL_NUMERIC; - memcpy(acl.address.ip.octet, ip_dst, IPV6_LEN); - memset(acl.address.ip.mask, 0xff, IPV6_LEN); - } else { - /* - * At this point we're either a hostname or an - * IP address with a slash. - */ - p = strchr(location, '/'); - if (p != NULL) { - /* - * We have a slash, so it's intended to be an - * IP address with mask - */ - *p = '\0'; - if (full_inet_pton(location, ip_dst) <= 0) - return -1; - - acl.type = ACL_NUMERIC; - memcpy(acl.address.ip.octet, ip_dst, IPV6_LEN); - - if (fill_netmask_array(p + 1, &(acl.address.ip.mask[0]), IPV6_LEN) < 0) - return -1; - } else { - /* In all likelihood a string */ - acl.type = ACL_STRING; - acl.address.string = safestrdup(location); - if (!acl.address.string) - return -1; - } - } - - /* - * Add the entry and then clean up. - */ - ret = vector_append(access_list, &acl, sizeof(struct acl_s)); - safefree(acl.address.string); - return ret; + struct acl_s acl; + int ret; + char *p, ip_dst[IPV6_LEN]; + + assert (location != NULL); + + /* + * If the access list has not been set up, create it. + */ + if (!access_list) + { + access_list = vector_create (); + if (!access_list) + { + log_message (LOG_ERR, "Unable to allocate memory for access list"); + return -1; + } + } + + /* + * Start populating the access control structure. + */ + memset (&acl, 0, sizeof (struct acl_s)); + acl.access = access_type; + + /* + * Check for a valid IP address (the simplest case) first. + */ + if (full_inet_pton (location, ip_dst) > 0) + { + acl.type = ACL_NUMERIC; + memcpy (acl.address.ip.octet, ip_dst, IPV6_LEN); + memset (acl.address.ip.mask, 0xff, IPV6_LEN); + } + else + { + /* + * At this point we're either a hostname or an + * IP address with a slash. + */ + p = strchr (location, '/'); + if (p != NULL) + { + /* + * We have a slash, so it's intended to be an + * IP address with mask + */ + *p = '\0'; + if (full_inet_pton (location, ip_dst) <= 0) + return -1; + + acl.type = ACL_NUMERIC; + memcpy (acl.address.ip.octet, ip_dst, IPV6_LEN); + + if (fill_netmask_array (p + 1, &(acl.address.ip.mask[0]), IPV6_LEN) + < 0) + return -1; + } + else + { + /* In all likelihood a string */ + acl.type = ACL_STRING; + acl.address.string = safestrdup (location); + if (!acl.address.string) + return -1; + } + } + + /* + * Add the entry and then clean up. + */ + ret = vector_append (access_list, &acl, sizeof (struct acl_s)); + safefree (acl.address.string); + return ret; } /* @@ -195,73 +211,79 @@ insert_acl(char *location, acl_access_t access_type) * -1 if no tests match, so skip */ static int -acl_string_processing(struct acl_s *acl, - const char *ip_address, const char *string_address) +acl_string_processing (struct acl_s *acl, + const char *ip_address, const char *string_address) { - int match; - struct addrinfo hints, *res, *ressave; - size_t test_length, match_length; - char ipbuf[512]; - - assert(acl && acl->type == ACL_STRING); - assert(ip_address && strlen(ip_address) > 0); - assert(string_address && strlen(string_address) > 0); - - /* - * If the first character of the ACL string is a period, we need to - * do a string based test only; otherwise, we can do a reverse - * lookup test as well. - */ - if (acl->address.string[0] != '.') { - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - if (getaddrinfo(acl->address.string, NULL, &hints, &res) != 0) - goto STRING_TEST; - - ressave = res; - - match = FALSE; - do { - get_ip_string(res->ai_addr, ipbuf, sizeof(ipbuf)); - if (strcmp(ip_address, ipbuf) == 0) { - match = TRUE; - break; - } - } while ((res = res->ai_next) != NULL); - - freeaddrinfo(ressave); - - if (match) { - if (acl->access == ACL_DENY) - return 0; - else - return 1; - } - } - - STRING_TEST: - test_length = strlen(string_address); - match_length = strlen(acl->address.string); - - /* - * 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. - */ - if (test_length < match_length) - return -1; - - if (strcasecmp - (string_address + (test_length - match_length), - acl->address.string) == 0) { - if (acl->access == ACL_DENY) - return 0; - else - return 1; - } - - /* Indicate that no tests succeeded, so skip to next control. */ - return -1; + int match; + struct addrinfo hints, *res, *ressave; + size_t test_length, match_length; + char ipbuf[512]; + + assert (acl && acl->type == ACL_STRING); + assert (ip_address && strlen (ip_address) > 0); + assert (string_address && strlen (string_address) > 0); + + /* + * If the first character of the ACL string is a period, we need to + * do a string based test only; otherwise, we can do a reverse + * lookup test as well. + */ + if (acl->address.string[0] != '.') + { + memset (&hints, 0, sizeof (struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + if (getaddrinfo (acl->address.string, NULL, &hints, &res) != 0) + goto STRING_TEST; + + ressave = res; + + match = FALSE; + do + { + get_ip_string (res->ai_addr, ipbuf, sizeof (ipbuf)); + if (strcmp (ip_address, ipbuf) == 0) + { + match = TRUE; + break; + } + } + while ((res = res->ai_next) != NULL); + + freeaddrinfo (ressave); + + if (match) + { + if (acl->access == ACL_DENY) + return 0; + else + return 1; + } + } + +STRING_TEST: + test_length = strlen (string_address); + match_length = strlen (acl->address.string); + + /* + * 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. + */ + if (test_length < match_length) + return -1; + + if (strcasecmp + (string_address + (test_length - match_length), + acl->address.string) == 0) + { + if (acl->access == ACL_DENY) + return 0; + else + return 1; + } + + /* Indicate that no tests succeeded, so skip to next control. */ + return -1; } /* @@ -273,28 +295,29 @@ acl_string_processing(struct acl_s *acl, * -1 neither allowed nor denied. */ 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; - int i; + uint8_t addr[IPV6_LEN], x, y; + int i; - assert(acl && acl->type == ACL_NUMERIC); - assert(ip && strlen(ip) > 0); + assert (acl && acl->type == ACL_NUMERIC); + assert (ip && strlen (ip) > 0); - if (full_inet_pton(ip, &addr) <= 0) - return -1; + if (full_inet_pton (ip, &addr) <= 0) + return -1; - 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]; + 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]; - /* If x and y don't match, the IP addresses don't match */ - if (x != y) - return 0; - } + /* If x and y don't match, the IP addresses don't match */ + if (x != y) + return 0; + } - /* The addresses match, return the permission */ - return (acl->access == ACL_ALLOW); + /* The addresses match, return the permission */ + return (acl->access == ACL_ALLOW); } /* @@ -305,50 +328,52 @@ check_numeric_acl(const struct acl_s *acl, const char *ip) * 0 if denied */ 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; - int perm; - size_t i; - - assert(fd >= 0); - assert(ip != NULL); - assert(host != NULL); - - /* - * If there is no access list allow everything. - */ - if (!access_list) - return 1; - - for (i = 0; i != vector_length(access_list); ++i) { - acl = vector_getentry(access_list, i, NULL); - switch (acl->type) { - case ACL_STRING: - perm = acl_string_processing(acl, ip, host); - break; - - case ACL_NUMERIC: - if (ip[0] == '\0') - continue; - perm = check_numeric_acl(acl, ip); - break; - } - - /* - * Check the return value too see if the IP address is - * allowed or denied. - */ - if (perm == 0) - break; - else if (perm == 1) - return perm; - } - - /* - * Deny all connections by default. - */ - log_message(LOG_NOTICE, "Unauthorized connection from \"%s\" [%s].", - host, ip); - return 0; + struct acl_s *acl; + int perm; + size_t i; + + assert (fd >= 0); + assert (ip != NULL); + assert (host != NULL); + + /* + * If there is no access list allow everything. + */ + if (!access_list) + return 1; + + for (i = 0; i != vector_length (access_list); ++i) + { + acl = vector_getentry (access_list, i, NULL); + switch (acl->type) + { + case ACL_STRING: + perm = acl_string_processing (acl, ip, host); + break; + + case ACL_NUMERIC: + if (ip[0] == '\0') + continue; + perm = check_numeric_acl (acl, ip); + break; + } + + /* + * Check the return value too see if the IP address is + * allowed or denied. + */ + if (perm == 0) + break; + else if (perm == 1) + return perm; + } + + /* + * Deny all connections by default. + */ + log_message (LOG_NOTICE, "Unauthorized connection from \"%s\" [%s].", + host, ip); + return 0; } @@ -21,10 +21,11 @@ #ifndef 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 check_acl(int fd, const char *ip_address, - const char *string_address); +extern int insert_acl (char *location, acl_access_t access_type); +extern int check_acl (int fd, const char *ip_address, + const char *string_address); #endif diff --git a/src/anonymous.c b/src/anonymous.c index 488d278..dd16421 100644 --- a/src/anonymous.c +++ b/src/anonymous.c @@ -30,9 +30,9 @@ static hashmap_t anonymous_map = NULL; 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. */ int -anonymous_search(char *s) +anonymous_search (char *s) { - assert(s != NULL); - assert(anonymous_map != NULL); + assert (s != 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. */ int -anonymous_insert(char *s) +anonymous_insert (char *s) { - char data = 1; + char data = 1; - assert(s != NULL); + assert (s != NULL); - if (!anonymous_map) { - anonymous_map = hashmap_create(32); - if (!anonymous_map) - return -1; - } + if (!anonymous_map) + { + anonymous_map = hashmap_create (32); + if (!anonymous_map) + return -1; + } - if (hashmap_search(anonymous_map, s) > 0) { - /* The key was already found, so return a positive number. */ - return 0; - } + if (hashmap_search (anonymous_map, s) > 0) + { + /* The key was already found, so return a positive number. */ + return 0; + } - /* Insert the new key */ - return hashmap_insert(anonymous_map, s, &data, sizeof(data)); + /* Insert the new key */ + return hashmap_insert (anonymous_map, s, &data, sizeof (data)); } diff --git a/src/anonymous.h b/src/anonymous.h index c3a01be..b6c93be 100644 --- a/src/anonymous.h +++ b/src/anonymous.h @@ -21,8 +21,8 @@ #ifndef _TINYPROXY_ANONYMOUS_H_ #define _TINYPROXY_ANONYMOUS_H_ -extern short int is_anonymous_enabled(void); -extern int anonymous_search(char *s); -extern int anonymous_insert(char *s); +extern short int is_anonymous_enabled (void); +extern int anonymous_search (char *s); +extern int anonymous_insert (char *s); #endif diff --git a/src/buffer.c b/src/buffer.c index 75bd59b..34aeefb 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -34,21 +34,23 @@ #define BUFFER_HEAD(x) (x)->head #define BUFFER_TAIL(x) (x)->tail -struct bufline_s { - unsigned char *string; /* the actual string of data */ - struct bufline_s *next; /* pointer to next in linked list */ - size_t length; /* length of the string of data */ - size_t pos; /* start sending from this offset */ +struct bufline_s +{ + unsigned char *string; /* the actual string of data */ + struct bufline_s *next; /* pointer to next in linked list */ + 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 * (and includes the total size) */ -struct buffer_s { - struct bufline_s *head; /* top of the buffer */ - struct bufline_s *tail; /* bottom of the buffer */ - size_t size; /* total size of the buffer */ +struct buffer_s +{ + struct bufline_s *head; /* top 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. */ 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(length > 0); + assert (data != NULL); + assert (length > 0); - if (!(newline = safemalloc(sizeof(struct bufline_s)))) - return NULL; + if (!(newline = safemalloc (sizeof (struct bufline_s)))) + return NULL; - if (!(newline->string = safemalloc(length))) { - safefree(newline); - return NULL; - } + if (!(newline->string = safemalloc (length))) + { + safefree (newline); + return NULL; + } - memcpy(newline->string, data, length); + memcpy (newline->string, data, length); - newline->next = NULL; - newline->length = length; + newline->next = NULL; + newline->length = length; - /* Position our "read" pointer at the beginning of the data */ - newline->pos = 0; + /* Position our "read" pointer at the beginning of the data */ + newline->pos = 0; - return newline; + return newline; } /* * Free the allocated buffer line */ static void -free_line(struct bufline_s *line) +free_line (struct bufline_s *line) { - assert(line != NULL); + assert (line != NULL); - if (!line) - return; + if (!line) + return; - if (line->string) - safefree(line->string); + if (line->string) + safefree (line->string); - safefree(line); + safefree (line); } /* * Create a new buffer */ struct buffer_s * -new_buffer(void) +new_buffer (void) { - struct buffer_s *buffptr; + struct buffer_s *buffptr; - if (!(buffptr = safemalloc(sizeof(struct buffer_s)))) - return NULL; + if (!(buffptr = safemalloc (sizeof (struct buffer_s)))) + return NULL; - /* - * Since the buffer is initially empty, set the HEAD and TAIL - * pointers to NULL since they can't possibly point anywhere at the - * moment. - */ - BUFFER_HEAD(buffptr) = BUFFER_TAIL(buffptr) = NULL; - buffptr->size = 0; + /* + * Since the buffer is initially empty, set the HEAD and TAIL + * pointers to NULL since they can't possibly point anywhere at the + * moment. + */ + BUFFER_HEAD (buffptr) = BUFFER_TAIL (buffptr) = NULL; + buffptr->size = 0; - return buffptr; + return buffptr; } /* * Delete all the lines in the buffer and the buffer itself */ 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)) { - next = BUFFER_HEAD(buffptr)->next; - free_line(BUFFER_HEAD(buffptr)); - BUFFER_HEAD(buffptr) = next; - } + while (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. */ 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. */ 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; - - assert(buffptr != NULL); - assert(data != NULL); - assert(length > 0); - - /* - * Sanity check here. A buffer with a non-NULL head pointer must - * have a size greater than zero, and vice-versa. - */ - if (BUFFER_HEAD(buffptr) == NULL) - assert(buffptr->size == 0); - else - assert(buffptr->size > 0); - - /* - * Make a new line so we can add it to the buffer. - */ - if (!(newline = makenewline(data, length))) - return -1; - - if (buffptr->size == 0) - BUFFER_HEAD(buffptr) = BUFFER_TAIL(buffptr) = newline; - else { - BUFFER_TAIL(buffptr)->next = newline; - BUFFER_TAIL(buffptr) = newline; - } - - buffptr->size += length; - - return 0; + struct bufline_s *newline; + + assert (buffptr != NULL); + assert (data != NULL); + assert (length > 0); + + /* + * Sanity check here. A buffer with a non-NULL head pointer must + * have a size greater than zero, and vice-versa. + */ + if (BUFFER_HEAD (buffptr) == NULL) + assert (buffptr->size == 0); + else + assert (buffptr->size > 0); + + /* + * Make a new line so we can add it to the buffer. + */ + if (!(newline = makenewline (data, length))) + return -1; + + if (buffptr->size == 0) + BUFFER_HEAD (buffptr) = BUFFER_TAIL (buffptr) = newline; + else + { + BUFFER_TAIL (buffptr)->next = newline; + BUFFER_TAIL (buffptr) = newline; + } + + buffptr->size += length; + + return 0; } /* * Remove the first line from the top of the buffer */ 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(BUFFER_HEAD(buffptr) != NULL); + assert (buffptr != NULL); + assert (BUFFER_HEAD (buffptr) != NULL); - line = BUFFER_HEAD(buffptr); - BUFFER_HEAD(buffptr) = line->next; + line = BUFFER_HEAD (buffptr); + 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) ssize_t -read_buffer(int fd, struct buffer_s * buffptr) +read_buffer (int fd, struct buffer_s * buffptr) { - ssize_t bytesin; - unsigned char *buffer; - - assert(fd >= 0); - assert(buffptr != NULL); - - /* - * Don't allow the buffer to grow larger than MAXBUFFSIZE - */ - if (buffptr->size >= MAXBUFFSIZE) - return 0; - - buffer = safemalloc(READ_BUFFER_SIZE); - if (!buffer) { - return -ENOMEM; - } - - bytesin = read(fd, buffer, READ_BUFFER_SIZE); - - if (bytesin > 0) { - if (add_to_buffer(buffptr, buffer, bytesin) < 0) { - log_message(LOG_ERR, - "readbuff: add_to_buffer() error."); - bytesin = -1; - } - } else { - if (bytesin == 0) { - /* connection was closed by client */ - bytesin = -1; - } else { - switch (errno) { + ssize_t bytesin; + unsigned char *buffer; + + assert (fd >= 0); + assert (buffptr != NULL); + + /* + * Don't allow the buffer to grow larger than MAXBUFFSIZE + */ + if (buffptr->size >= MAXBUFFSIZE) + return 0; + + buffer = safemalloc (READ_BUFFER_SIZE); + if (!buffer) + { + return -ENOMEM; + } + + bytesin = read (fd, buffer, READ_BUFFER_SIZE); + + if (bytesin > 0) + { + if (add_to_buffer (buffptr, buffer, bytesin) < 0) + { + log_message (LOG_ERR, "readbuff: add_to_buffer() error."); + bytesin = -1; + } + } + else + { + if (bytesin == 0) + { + /* connection was closed by client */ + bytesin = -1; + } + else + { + switch (errno) + { #ifdef EWOULDBLOCK - case EWOULDBLOCK: + case EWOULDBLOCK: #else # ifdef EAGAIN - case EAGAIN: + case EAGAIN: # endif #endif - case EINTR: - bytesin = 0; - break; - default: - log_message(LOG_ERR, - "readbuff: recv() error \"%s\" on file descriptor %d", - strerror(errno), fd); - bytesin = -1; - break; - } - } - } - - safefree(buffer); - return bytesin; + case EINTR: + bytesin = 0; + break; + default: + log_message (LOG_ERR, + "readbuff: recv() error \"%s\" on file descriptor %d", + strerror (errno), fd); + bytesin = -1; + break; + } + } + } + + safefree (buffer); + return bytesin; } /* @@ -276,53 +289,57 @@ read_buffer(int fd, struct buffer_s * buffptr) * Takes a connection and returns the number of bytes written. */ ssize_t -write_buffer(int fd, struct buffer_s * buffptr) +write_buffer (int fd, struct buffer_s * buffptr) { - ssize_t bytessent; - struct bufline_s *line; - - assert(fd >= 0); - assert(buffptr != NULL); - - if (buffptr->size == 0) - return 0; - - /* Sanity check. It would be bad to be using a NULL pointer! */ - assert(BUFFER_HEAD(buffptr) != NULL); - line = BUFFER_HEAD(buffptr); - - bytessent = - send(fd, line->string + line->pos, line->length - line->pos, - MSG_NOSIGNAL); - - if (bytessent >= 0) { - /* bytes sent, adjust buffer */ - line->pos += bytessent; - if (line->pos == line->length) - free_line(remove_from_buffer(buffptr)); - return bytessent; - } else { - switch (errno) { + ssize_t bytessent; + struct bufline_s *line; + + assert (fd >= 0); + assert (buffptr != NULL); + + if (buffptr->size == 0) + return 0; + + /* Sanity check. It would be bad to be using a NULL pointer! */ + assert (BUFFER_HEAD (buffptr) != NULL); + line = BUFFER_HEAD (buffptr); + + bytessent = + send (fd, line->string + line->pos, line->length - line->pos, + MSG_NOSIGNAL); + + if (bytessent >= 0) + { + /* bytes sent, adjust buffer */ + line->pos += bytessent; + if (line->pos == line->length) + free_line (remove_from_buffer (buffptr)); + return bytessent; + } + else + { + switch (errno) + { #ifdef EWOULDBLOCK - case EWOULDBLOCK: + case EWOULDBLOCK: #else # ifdef EAGAIN - case EAGAIN: + case EAGAIN: # endif #endif - case EINTR: - return 0; - case ENOBUFS: - case ENOMEM: - log_message(LOG_ERR, - "writebuff: write() error [NOBUFS/NOMEM] \"%s\" on file descriptor %d", - strerror(errno), fd); - return 0; - default: - log_message(LOG_ERR, - "writebuff: write() error \"%s\" on file descriptor %d", - strerror(errno), fd); - return -1; - } - } + case EINTR: + return 0; + case ENOBUFS: + case ENOMEM: + log_message (LOG_ERR, + "writebuff: write() error [NOBUFS/NOMEM] \"%s\" on file descriptor %d", + strerror (errno), fd); + return 0; + default: + log_message (LOG_ERR, + "writebuff: write() error \"%s\" on file descriptor %d", + strerror (errno), fd); + return -1; + } + } } diff --git a/src/buffer.h b/src/buffer.h index cb4d245..ff1167f 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -24,17 +24,17 @@ /* Forward declaration */ struct buffer_s; -extern struct buffer_s *new_buffer(void); -extern void delete_buffer(struct buffer_s *buffptr); -extern size_t buffer_size(struct buffer_s *buffptr); +extern struct buffer_s *new_buffer (void); +extern void delete_buffer (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. */ -extern int add_to_buffer(struct buffer_s *buffptr, unsigned char *data, - size_t length); +extern int add_to_buffer (struct buffer_s *buffptr, unsigned char *data, + size_t length); -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 read_buffer (int fd, struct buffer_s *buffptr); +extern ssize_t write_buffer (int fd, struct buffer_s *buffptr); -#endif /* __BUFFER_H_ */ +#endif /* __BUFFER_H_ */ diff --git a/src/child.c b/src/child.c index 1bb1802..25b95b8 100644 --- a/src/child.c +++ b/src/child.c @@ -37,11 +37,13 @@ static socklen_t addrlen; /* * Stores the internal data needed for each child (connection) */ -enum child_status_t { T_EMPTY, T_WAITING, T_CONNECTED }; -struct child_s { - pid_t tid; - unsigned int connects; - enum child_status_t status; +enum child_status_t +{ T_EMPTY, T_WAITING, T_CONNECTED }; +struct child_s +{ + 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_config_s { - int maxclients, maxrequestsperchild; - int maxspareservers, minspareservers, startservers; +static struct child_config_s +{ + int maxclients, maxrequestsperchild; + int maxspareservers, minspareservers, startservers; } 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 @@ -74,47 +77,48 @@ static struct flock lock_it, unlock_it; static int lock_fd = -1; 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 - * of glibc so that mkstemp() doesn't make us vulnerable. - */ - umask(0177); + /* Only allow u+rw bits. This may be required for some versions + * of glibc so that mkstemp() doesn't make us vulnerable. + */ + umask (0177); - lock_fd = mkstemp(lock_file); - unlink(lock_file); + lock_fd = mkstemp (lock_file); + unlink (lock_file); - lock_it.l_type = F_WRLCK; - lock_it.l_whence = SEEK_SET; - lock_it.l_start = 0; - lock_it.l_len = 0; + lock_it.l_type = F_WRLCK; + lock_it.l_whence = SEEK_SET; + lock_it.l_start = 0; + lock_it.l_len = 0; - unlock_it.l_type = F_UNLCK; - unlock_it.l_whence = SEEK_SET; - unlock_it.l_start = 0; - unlock_it.l_len = 0; + unlock_it.l_type = F_UNLCK; + unlock_it.l_whence = SEEK_SET; + unlock_it.l_start = 0; + unlock_it.l_len = 0; } static void -_child_lock_wait(void) +_child_lock_wait (void) { - int rc; - - while ((rc = fcntl(lock_fd, F_SETLKW, &lock_it)) < 0) { - if (errno == EINTR) - continue; - else - return; - } + int rc; + + while ((rc = fcntl (lock_fd, F_SETLKW, &lock_it)) < 0) + { + if (errno == EINTR) + continue; + else + return; + } } static void -_child_lock_release(void) +_child_lock_release (void) { - if (fcntl(lock_fd, F_SETLKW, &unlock_it) < 0) - return; + if (fcntl (lock_fd, F_SETLKW, &unlock_it) < 0) + return; } /* END OF LOCKING SECTION */ @@ -138,126 +142,133 @@ _child_lock_release(void) * Set the configuration values for the various child related settings. */ short int -child_configure(child_config_t type, int val) +child_configure (child_config_t type, int val) { - switch (type) { - case CHILD_MAXCLIENTS: - child_config.maxclients = val; - break; - case CHILD_MAXSPARESERVERS: - child_config.maxspareservers = val; - break; - case CHILD_MINSPARESERVERS: - child_config.minspareservers = val; - break; - case CHILD_STARTSERVERS: - child_config.startservers = val; - break; - case CHILD_MAXREQUESTSPERCHILD: - child_config.maxrequestsperchild = val; - break; - default: - DEBUG2("Invalid type (%d)", type); - return -1; - } - - return 0; + switch (type) + { + case CHILD_MAXCLIENTS: + child_config.maxclients = val; + break; + case CHILD_MAXSPARESERVERS: + child_config.maxspareservers = val; + break; + case CHILD_MINSPARESERVERS: + child_config.minspareservers = val; + break; + case CHILD_STARTSERVERS: + child_config.startservers = val; + break; + case CHILD_MAXREQUESTSPERCHILD: + child_config.maxrequestsperchild = val; + break; + default: + DEBUG2 ("Invalid type (%d)", type); + return -1; + } + + return 0; } /* * This is the main (per child) loop. */ static void -child_main(struct child_s *ptr) +child_main (struct child_s *ptr) { - int connfd; - struct sockaddr *cliaddr; - socklen_t clilen; + int connfd; + struct sockaddr *cliaddr; + socklen_t clilen; - cliaddr = safemalloc(addrlen); - if (!cliaddr) { - log_message(LOG_CRIT, - "Could not allocate memory for child address."); - exit(0); - } + cliaddr = safemalloc (addrlen); + if (!cliaddr) + { + log_message (LOG_CRIT, "Could not allocate memory for child address."); + exit (0); + } - ptr->connects = 0; + ptr->connects = 0; - while (!config.quit) { - ptr->status = T_WAITING; + while (!config.quit) + { + ptr->status = T_WAITING; - clilen = addrlen; + clilen = addrlen; - connfd = accept(listenfd, cliaddr, &clilen); + connfd = accept (listenfd, cliaddr, &clilen); #ifndef NDEBUG - /* - * Enable the TINYPROXY_DEBUG environment variable if you - * want to use the GDB debugger. - */ - if (getenv("TINYPROXY_DEBUG")) { - /* Pause for 10 seconds to allow us to connect debugger */ - fprintf(stderr, - "Process has accepted connection: %ld\n", - (long int)ptr->tid); - sleep(10); - fprintf(stderr, "Continuing process: %ld\n", - (long int)ptr->tid); - } + /* + * Enable the TINYPROXY_DEBUG environment variable if you + * want to use the GDB debugger. + */ + if (getenv ("TINYPROXY_DEBUG")) + { + /* Pause for 10 seconds to allow us to connect debugger */ + fprintf (stderr, + "Process has accepted connection: %ld\n", + (long int) ptr->tid); + sleep (10); + fprintf (stderr, "Continuing process: %ld\n", (long int) ptr->tid); + } #endif - /* - * Make sure no error occurred... - */ - if (connfd < 0) { - log_message(LOG_ERR, - "Accept returned an error (%s) ... retrying.", - strerror(errno)); - continue; - } - - ptr->status = T_CONNECTED; - - SERVER_DEC(); - - handle_connection(connfd); - ptr->connects++; - - if (child_config.maxrequestsperchild != 0) { - DEBUG2("%u connections so far...", ptr->connects); - - if (ptr->connects == child_config.maxrequestsperchild) { - log_message(LOG_NOTICE, - "Child has reached MaxRequestsPerChild (%u). Killing child.", - ptr->connects); - break; - } - } - - SERVER_COUNT_LOCK(); - if (*servers_waiting > child_config.maxspareservers) { - /* - * There are too many spare children, kill ourself - * off. - */ - log_message(LOG_NOTICE, - "Waiting servers (%d) exceeds MaxSpareServers (%d). Killing child.", - *servers_waiting, - child_config.maxspareservers); - SERVER_COUNT_UNLOCK(); - - break; - } else { - SERVER_COUNT_UNLOCK(); - } - - SERVER_INC(); - } - - ptr->status = T_EMPTY; - - safefree(cliaddr); - exit(0); + /* + * Make sure no error occurred... + */ + if (connfd < 0) + { + log_message (LOG_ERR, + "Accept returned an error (%s) ... retrying.", + strerror (errno)); + continue; + } + + ptr->status = T_CONNECTED; + + SERVER_DEC (); + + handle_connection (connfd); + ptr->connects++; + + if (child_config.maxrequestsperchild != 0) + { + DEBUG2 ("%u connections so far...", ptr->connects); + + if (ptr->connects == child_config.maxrequestsperchild) + { + log_message (LOG_NOTICE, + "Child has reached MaxRequestsPerChild (%u). Killing child.", + ptr->connects); + break; + } + } + + SERVER_COUNT_LOCK (); + if (*servers_waiting > child_config.maxspareservers) + { + /* + * There are too many spare children, kill ourself + * off. + */ + log_message (LOG_NOTICE, + "Waiting servers (%d) exceeds MaxSpareServers (%d). Killing child.", + *servers_waiting, child_config.maxspareservers); + SERVER_COUNT_UNLOCK (); + + break; + } + else + { + SERVER_COUNT_UNLOCK (); + } + + SERVER_INC (); + } + + ptr->status = T_EMPTY; + + safefree (cliaddr); + exit (0); } /* @@ -265,104 +276,113 @@ child_main(struct child_s *ptr) * child_main() function. */ 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) - return pid; /* parent */ + if ((pid = fork ()) > 0) + return pid; /* parent */ - /* - * Reset the SIGNALS so that the child can be reaped. - */ - set_signal_handler(SIGCHLD, SIG_DFL); - set_signal_handler(SIGTERM, SIG_DFL); - set_signal_handler(SIGHUP, SIG_DFL); + /* + * Reset the SIGNALS so that the child can be reaped. + */ + set_signal_handler (SIGCHLD, SIG_DFL); + set_signal_handler (SIGTERM, SIG_DFL); + set_signal_handler (SIGHUP, SIG_DFL); - child_main(ptr); /* never returns */ - return -1; + child_main (ptr); /* never returns */ + return -1; } /* * Create a pool of children to handle incoming connections */ short int -child_pool_create(void) +child_pool_create (void) { - unsigned int i; - - /* - * Make sure the number of MaxClients is not zero, since this - * variable determines the size of the array created for children - * later on. - */ - if (child_config.maxclients == 0) { - log_message(LOG_ERR, - "child_pool_create: \"MaxClients\" must be greater than zero."); - return -1; - } - if (child_config.startservers == 0) { - log_message(LOG_ERR, - "child_pool_create: \"StartServers\" must be greater than zero."); - return -1; - } - - child_ptr = calloc_shared_memory(child_config.maxclients, - sizeof(struct child_s)); - if (!child_ptr) { - log_message(LOG_ERR, "Could not allocate memory for children."); - return -1; - } - - servers_waiting = malloc_shared_memory(sizeof(unsigned int)); - if (servers_waiting == MAP_FAILED) { - log_message(LOG_ERR, - "Could not allocate memory for child counting."); - return -1; - } - *servers_waiting = 0; - - /* - * Create a "locking" file for use around the servers_waiting - * variable. - */ - _child_lock_init(); - - if (child_config.startservers > child_config.maxclients) { - log_message(LOG_WARNING, - "Can not start more than \"MaxClients\" servers. Starting %u servers instead.", - child_config.maxclients); - child_config.startservers = child_config.maxclients; - } - - for (i = 0; i != child_config.maxclients; i++) { - child_ptr[i].status = T_EMPTY; - child_ptr[i].connects = 0; - } - - for (i = 0; i != child_config.startservers; i++) { - DEBUG2("Trying to create child %d of %d", i + 1, - child_config.startservers); - child_ptr[i].status = T_WAITING; - child_ptr[i].tid = child_make(&child_ptr[i]); - - if (child_ptr[i].tid < 0) { - log_message(LOG_WARNING, - "Could not create child number %d of %d", - i, child_config.startservers); - return -1; - } else { - log_message(LOG_INFO, - "Creating child number %d of %d ...", - i + 1, child_config.startservers); - - SERVER_INC(); - } - } - - log_message(LOG_INFO, "Finished creating all children."); - - return 0; + unsigned int i; + + /* + * Make sure the number of MaxClients is not zero, since this + * variable determines the size of the array created for children + * later on. + */ + if (child_config.maxclients == 0) + { + log_message (LOG_ERR, + "child_pool_create: \"MaxClients\" must be greater than zero."); + return -1; + } + if (child_config.startservers == 0) + { + log_message (LOG_ERR, + "child_pool_create: \"StartServers\" must be greater than zero."); + return -1; + } + + child_ptr = calloc_shared_memory (child_config.maxclients, + sizeof (struct child_s)); + if (!child_ptr) + { + log_message (LOG_ERR, "Could not allocate memory for children."); + return -1; + } + + servers_waiting = malloc_shared_memory (sizeof (unsigned int)); + if (servers_waiting == MAP_FAILED) + { + log_message (LOG_ERR, "Could not allocate memory for child counting."); + return -1; + } + *servers_waiting = 0; + + /* + * Create a "locking" file for use around the servers_waiting + * variable. + */ + _child_lock_init (); + + if (child_config.startservers > child_config.maxclients) + { + log_message (LOG_WARNING, + "Can not start more than \"MaxClients\" servers. Starting %u servers instead.", + child_config.maxclients); + child_config.startservers = child_config.maxclients; + } + + for (i = 0; i != child_config.maxclients; i++) + { + child_ptr[i].status = T_EMPTY; + child_ptr[i].connects = 0; + } + + for (i = 0; i != child_config.startservers; i++) + { + DEBUG2 ("Trying to create child %d of %d", i + 1, + child_config.startservers); + child_ptr[i].status = T_WAITING; + child_ptr[i].tid = child_make (&child_ptr[i]); + + if (child_ptr[i].tid < 0) + { + log_message (LOG_WARNING, + "Could not create child number %d of %d", + i, child_config.startservers); + return -1; + } + else + { + log_message (LOG_INFO, + "Creating child number %d of %d ...", + i + 1, child_config.startservers); + + SERVER_INC (); + } + } + + log_message (LOG_INFO, "Finished creating all children."); + + return 0; } /* @@ -370,88 +390,95 @@ child_pool_create(void) * servers. It monitors this at least once a second. */ void -child_main_loop(void) +child_main_loop (void) { - unsigned int i; - - while (1) { - if (config.quit) - return; - - /* If there are not enough spare servers, create more */ - SERVER_COUNT_LOCK(); - if (*servers_waiting < child_config.minspareservers) { - log_message(LOG_NOTICE, - "Waiting servers (%d) is less than MinSpareServers (%d). Creating new child.", - *servers_waiting, - child_config.minspareservers); - - SERVER_COUNT_UNLOCK(); - - for (i = 0; i != child_config.maxclients; i++) { - if (child_ptr[i].status == T_EMPTY) { - child_ptr[i].status = T_WAITING; - child_ptr[i].tid = - child_make(&child_ptr[i]); - if (child_ptr[i].tid < 0) { - log_message(LOG_NOTICE, - "Could not create child"); - - child_ptr[i].status = T_EMPTY; - break; - } - - SERVER_INC(); - - break; - } - } - } else { - SERVER_COUNT_UNLOCK(); - } - - sleep(5); - - /* Handle log rotation if it was requested */ - if (received_sighup) { - truncate_log_file(); + unsigned int i; + + while (1) + { + if (config.quit) + return; + + /* If there are not enough spare servers, create more */ + SERVER_COUNT_LOCK (); + if (*servers_waiting < child_config.minspareservers) + { + log_message (LOG_NOTICE, + "Waiting servers (%d) is less than MinSpareServers (%d). Creating new child.", + *servers_waiting, child_config.minspareservers); + + SERVER_COUNT_UNLOCK (); + + for (i = 0; i != child_config.maxclients; i++) + { + if (child_ptr[i].status == T_EMPTY) + { + child_ptr[i].status = T_WAITING; + child_ptr[i].tid = child_make (&child_ptr[i]); + if (child_ptr[i].tid < 0) + { + log_message (LOG_NOTICE, "Could not create child"); + + child_ptr[i].status = T_EMPTY; + break; + } + + SERVER_INC (); + + break; + } + } + } + else + { + SERVER_COUNT_UNLOCK (); + } + + sleep (5); + + /* Handle log rotation if it was requested */ + if (received_sighup) + { + truncate_log_file (); #ifdef FILTER_ENABLE - if (config.filter) { - filter_destroy(); - filter_init(); - } - log_message(LOG_NOTICE, "Re-reading filter file."); -#endif /* FILTER_ENABLE */ - - received_sighup = FALSE; - } - } + if (config.filter) + { + filter_destroy (); + filter_init (); + } + log_message (LOG_NOTICE, "Re-reading filter file."); +#endif /* FILTER_ENABLE */ + + received_sighup = FALSE; + } + } } /* * Go through all the non-empty children and cancel them. */ void -child_kill_children(void) +child_kill_children (void) { - unsigned int i; + unsigned int i; - for (i = 0; i != child_config.maxclients; i++) { - if (child_ptr[i].status != T_EMPTY) - kill(child_ptr[i].tid, SIGTERM); - } + for (i = 0; i != child_config.maxclients; i++) + { + if (child_ptr[i].status != T_EMPTY) + kill (child_ptr[i].tid, SIGTERM); + } } int -child_listening_sock(uint16_t port) +child_listening_sock (uint16_t port) { - listenfd = listen_sock(port, &addrlen); - return listenfd; + listenfd = listen_sock (port, &addrlen); + return listenfd; } void -child_close_sock(void) +child_close_sock (void) { - close(listenfd); + close (listenfd); } diff --git a/src/child.h b/src/child.h index 65fbb9f..dc19360 100644 --- a/src/child.h +++ b/src/child.h @@ -21,20 +21,21 @@ #ifndef TINYPROXY_CHILD_H #define TINYPROXY_CHILD_H -typedef enum { - CHILD_MAXCLIENTS, - CHILD_MAXSPARESERVERS, - CHILD_MINSPARESERVERS, - CHILD_STARTSERVERS, - CHILD_MAXREQUESTSPERCHILD +typedef enum +{ + CHILD_MAXCLIENTS, + CHILD_MAXSPARESERVERS, + CHILD_MINSPARESERVERS, + CHILD_STARTSERVERS, + CHILD_MAXREQUESTSPERCHILD } child_config_t; -extern short int child_pool_create(void); -extern int child_listening_sock(uint16_t port); -extern void child_close_sock(void); -extern void child_main_loop(void); -extern void child_kill_children(void); +extern short int child_pool_create (void); +extern int child_listening_sock (uint16_t port); +extern void child_close_sock (void); +extern void child_main_loop (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 diff --git a/src/common.h b/src/common.h index 551d0f9..ab71322 100644 --- a/src/common.h +++ b/src/common.h @@ -173,13 +173,13 @@ # define MSG_NOSIGNAL (0) #endif -#ifndef SHUT_RD /* these three Posix.1g names are quite new */ -# define SHUT_RD 0 /* shutdown for reading */ -# define SHUT_WR 1 /* shutdown for writing */ -# define SHUT_RDWR 2 /* shutdown for reading and writing */ +#ifndef SHUT_RD /* these three Posix.1g names are quite new */ +# define SHUT_RD 0 /* shutdown for reading */ +# define SHUT_WR 1 /* shutdown for writing */ +# define SHUT_RDWR 2 /* shutdown for reading and writing */ #endif -#define MAXLISTEN 1024 /* Max number of connections */ +#define MAXLISTEN 1024 /* Max number of connections */ /* * SunOS doesn't have INADDR_NONE defined. diff --git a/src/conffile.c b/src/conffile.c index 78f5da3..85bab7e 100644 --- a/src/conffile.c +++ b/src/conffile.c @@ -66,7 +66,8 @@ * All configuration handling functions are REQUIRED to be defined * with the same function template as below. */ -typedef int (*CONFFILE_HANDLER) (struct config_s *, const char *, regmatch_t[]); +typedef int (*CONFFILE_HANDLER) (struct config_s *, const char *, + regmatch_t[]); /* * Define the pattern used by any directive handling function. The @@ -86,55 +87,55 @@ typedef int (*CONFFILE_HANDLER) (struct config_s *, const char *, regmatch_t[]); * to be in-scope before the big structure below. */ static -HANDLE_FUNC(handle_nop) +HANDLE_FUNC (handle_nop) { - return 0; -} /* do nothing function */ + return 0; +} /* do nothing function */ -static HANDLE_FUNC(handle_allow); -static HANDLE_FUNC(handle_anonymous); -static HANDLE_FUNC(handle_bind); -static HANDLE_FUNC(handle_bindsame); -static HANDLE_FUNC(handle_connectport); -static HANDLE_FUNC(handle_defaulterrorfile); -static HANDLE_FUNC(handle_deny); -static HANDLE_FUNC(handle_errorfile); +static HANDLE_FUNC (handle_allow); +static HANDLE_FUNC (handle_anonymous); +static HANDLE_FUNC (handle_bind); +static HANDLE_FUNC (handle_bindsame); +static HANDLE_FUNC (handle_connectport); +static HANDLE_FUNC (handle_defaulterrorfile); +static HANDLE_FUNC (handle_deny); +static HANDLE_FUNC (handle_errorfile); #ifdef FILTER_ENABLE -static HANDLE_FUNC(handle_filter); -static HANDLE_FUNC(handle_filtercasesensitive); -static HANDLE_FUNC(handle_filterdefaultdeny); -static HANDLE_FUNC(handle_filterextended); -static HANDLE_FUNC(handle_filterurls); +static HANDLE_FUNC (handle_filter); +static HANDLE_FUNC (handle_filtercasesensitive); +static HANDLE_FUNC (handle_filterdefaultdeny); +static HANDLE_FUNC (handle_filterextended); +static HANDLE_FUNC (handle_filterurls); #endif -static HANDLE_FUNC(handle_group); -static HANDLE_FUNC(handle_listen); -static HANDLE_FUNC(handle_logfile); -static HANDLE_FUNC(handle_loglevel); -static HANDLE_FUNC(handle_maxclients); -static HANDLE_FUNC(handle_maxrequestsperchild); -static HANDLE_FUNC(handle_maxspareservers); -static HANDLE_FUNC(handle_minspareservers); -static HANDLE_FUNC(handle_pidfile); -static HANDLE_FUNC(handle_port); +static HANDLE_FUNC (handle_group); +static HANDLE_FUNC (handle_listen); +static HANDLE_FUNC (handle_logfile); +static HANDLE_FUNC (handle_loglevel); +static HANDLE_FUNC (handle_maxclients); +static HANDLE_FUNC (handle_maxrequestsperchild); +static HANDLE_FUNC (handle_maxspareservers); +static HANDLE_FUNC (handle_minspareservers); +static HANDLE_FUNC (handle_pidfile); +static HANDLE_FUNC (handle_port); #ifdef REVERSE_SUPPORT -static HANDLE_FUNC(handle_reversebaseurl); -static HANDLE_FUNC(handle_reversemagic); -static HANDLE_FUNC(handle_reverseonly); -static HANDLE_FUNC(handle_reversepath); +static HANDLE_FUNC (handle_reversebaseurl); +static HANDLE_FUNC (handle_reversemagic); +static HANDLE_FUNC (handle_reverseonly); +static HANDLE_FUNC (handle_reversepath); #endif -static HANDLE_FUNC(handle_startservers); -static HANDLE_FUNC(handle_statfile); -static HANDLE_FUNC(handle_stathost); -static HANDLE_FUNC(handle_syslog); -static HANDLE_FUNC(handle_timeout); +static HANDLE_FUNC (handle_startservers); +static HANDLE_FUNC (handle_statfile); +static HANDLE_FUNC (handle_stathost); +static HANDLE_FUNC (handle_syslog); +static HANDLE_FUNC (handle_timeout); -static HANDLE_FUNC(handle_user); -static HANDLE_FUNC(handle_viaproxyname); -static HANDLE_FUNC(handle_xtinyproxy); +static HANDLE_FUNC (handle_user); +static HANDLE_FUNC (handle_viaproxyname); +static HANDLE_FUNC (handle_xtinyproxy); #ifdef UPSTREAM_SUPPORT -static HANDLE_FUNC(handle_upstream); -static HANDLE_FUNC(handle_upstream_no); +static HANDLE_FUNC (handle_upstream); +static HANDLE_FUNC (handle_upstream_no); #endif /* @@ -156,82 +157,77 @@ static HANDLE_FUNC(handle_upstream_no); * for internal use, a pointer to the compiled regex so it only needs * to be compiled one. */ -struct { - const char *re; - CONFFILE_HANDLER handler; - regex_t *cre; -} directives[] = { - /* comments */ - { BEGIN "#", handle_nop }, - - /* blank lines */ - { "^[[:space:]]+$", handle_nop }, - - /* string arguments */ - STDCONF("logfile", STR, handle_logfile), - STDCONF("pidfile", STR, handle_pidfile), - STDCONF("anonymous", STR, handle_anonymous), - STDCONF("viaproxyname", STR, handle_viaproxyname), - STDCONF("defaulterrorfile", STR, handle_defaulterrorfile), - STDCONF("statfile", STR, handle_statfile), - STDCONF("stathost", STR, handle_stathost), - STDCONF("xtinyproxy", STR, handle_xtinyproxy), - - /* boolean arguments */ - STDCONF("syslog", BOOL, handle_syslog), - STDCONF("bindsame", BOOL, handle_bindsame), - - /* integer arguments */ - STDCONF("port", INT, handle_port), - STDCONF("maxclients", INT, handle_maxclients), - STDCONF("maxspareservers", INT, handle_maxspareservers), - STDCONF("minspareservers", INT, handle_minspareservers), - STDCONF("startservers", INT, handle_startservers), - STDCONF("maxrequestsperchild", INT, handle_maxrequestsperchild), - STDCONF("timeout", INT, handle_timeout), - STDCONF("connectport", INT, handle_connectport), - - /* alphanumeric arguments */ - STDCONF("user", ALNUM, handle_user), - STDCONF("group", ALNUM, handle_group), - - /* ip arguments */ - STDCONF("listen", IP, handle_listen), - STDCONF("allow", "(" IPMASK "|" ALNUM ")", handle_allow), - STDCONF("deny", "(" IPMASK "|" ALNUM ")", handle_deny), - STDCONF("bind", IP, handle_bind), - - /* error files */ - STDCONF("errorfile", INT WS STR, handle_errorfile), - +struct +{ + const char *re; + CONFFILE_HANDLER handler; + regex_t *cre; +} directives[] = +{ + /* comments */ + { + BEGIN "#", handle_nop}, + /* blank lines */ + { + "^[[:space:]]+$", handle_nop}, + /* string arguments */ + STDCONF ("logfile", STR, handle_logfile), + STDCONF ("pidfile", STR, handle_pidfile), + STDCONF ("anonymous", STR, handle_anonymous), + STDCONF ("viaproxyname", STR, handle_viaproxyname), + STDCONF ("defaulterrorfile", STR, handle_defaulterrorfile), + STDCONF ("statfile", STR, handle_statfile), + STDCONF ("stathost", STR, handle_stathost), + STDCONF ("xtinyproxy", STR, handle_xtinyproxy), + /* boolean arguments */ + STDCONF ("syslog", BOOL, handle_syslog), + STDCONF ("bindsame", BOOL, handle_bindsame), + /* integer arguments */ + STDCONF ("port", INT, handle_port), + STDCONF ("maxclients", INT, handle_maxclients), + STDCONF ("maxspareservers", INT, handle_maxspareservers), + STDCONF ("minspareservers", INT, handle_minspareservers), + STDCONF ("startservers", INT, handle_startservers), + STDCONF ("maxrequestsperchild", INT, handle_maxrequestsperchild), + STDCONF ("timeout", INT, handle_timeout), + STDCONF ("connectport", INT, handle_connectport), + /* alphanumeric arguments */ + STDCONF ("user", ALNUM, handle_user), + STDCONF ("group", ALNUM, handle_group), + /* ip arguments */ + STDCONF ("listen", IP, handle_listen), + STDCONF ("allow", "(" IPMASK "|" ALNUM ")", handle_allow), + STDCONF ("deny", "(" IPMASK "|" ALNUM ")", handle_deny), + STDCONF ("bind", IP, handle_bind), + /* error files */ + STDCONF ("errorfile", INT WS STR, handle_errorfile), #ifdef FILTER_ENABLE - /* filtering */ - STDCONF("filter", STR, handle_filter), - STDCONF("filterurls", BOOL, handle_filterurls), - STDCONF("filterextended", BOOL, handle_filterextended), - STDCONF("filterdefaultdeny", BOOL, handle_filterdefaultdeny), - STDCONF("filtercasesensitive", BOOL, handle_filtercasesensitive), + /* filtering */ + STDCONF ("filter", STR, handle_filter), + STDCONF ("filterurls", BOOL, handle_filterurls), + STDCONF ("filterextended", BOOL, handle_filterextended), + STDCONF ("filterdefaultdeny", BOOL, handle_filterdefaultdeny), + STDCONF ("filtercasesensitive", BOOL, handle_filtercasesensitive), #endif - #ifdef REVERSE_SUPPORT - /* Reverse proxy arguments */ - STDCONF("reversebaseurl", STR, handle_reversebaseurl), - STDCONF("reverseonly", BOOL, handle_reverseonly), - STDCONF("reversemagic", BOOL, handle_reversemagic), - STDCONF("reversepath", STR WS "(" STR ")?", handle_reversepath), + /* Reverse proxy arguments */ + STDCONF ("reversebaseurl", STR, handle_reversebaseurl), + STDCONF ("reverseonly", BOOL, handle_reverseonly), + STDCONF ("reversemagic", BOOL, handle_reversemagic), + STDCONF ("reversepath", STR WS "(" STR ")?", handle_reversepath), #endif - #ifdef UPSTREAM_SUPPORT - /* upstream is rather complicated */ - { BEGIN "(no" WS "upstream)" WS STR END, handle_upstream_no }, - { BEGIN "(upstream)" WS "(" IP "|" ALNUM ")" ":" INT "(" WS STR ")?" END, handle_upstream }, + /* upstream is rather complicated */ + { + BEGIN "(no" WS "upstream)" WS STR END, handle_upstream_no}, + { + BEGIN "(upstream)" WS "(" IP "|" ALNUM ")" ":" INT "(" WS STR ")?" END, + handle_upstream}, #endif - - /* loglevel */ - STDCONF("loglevel", "(critical|error|warning|notice|connect|info)", - handle_loglevel) -}; -const unsigned int ndirectives = sizeof(directives) / sizeof(directives[0]); + /* loglevel */ +STDCONF ("loglevel", "(critical|error|warning|notice|connect|info)", + handle_loglevel)}; +const unsigned int ndirectives = sizeof (directives) / sizeof (directives[0]); /* * Compiles the regular expressions used by the configuration file. This @@ -240,25 +236,25 @@ const unsigned int ndirectives = sizeof(directives) / sizeof(directives[0]); * Returns 0 on success; negative upon failure. */ int -config_compile(void) +config_compile (void) { - int i, r; + int i, r; - for (i = 0; i != ndirectives; ++i) { - assert(directives[i].handler); - assert(!directives[i].cre); + for (i = 0; i != ndirectives; ++i) + { + assert (directives[i].handler); + assert (!directives[i].cre); - directives[i].cre = safemalloc(sizeof(regex_t)); - if (!directives[i].cre) - return -1; + directives[i].cre = safemalloc (sizeof (regex_t)); + if (!directives[i].cre) + return -1; - r = regcomp(directives[i].cre, - directives[i].re, - REG_EXTENDED | REG_ICASE | REG_NEWLINE); - if (r) - return r; - } - return 0; + r = regcomp (directives[i].cre, + directives[i].re, REG_EXTENDED | REG_ICASE | REG_NEWLINE); + if (r) + return r; + } + return 0; } /* @@ -270,39 +266,42 @@ config_compile(void) * a negative number is returned. */ static int -check_match(struct config_s *conf, const char *line) +check_match (struct config_s *conf, const char *line) { - regmatch_t match[RE_MAX_MATCHES]; - unsigned int i; + regmatch_t match[RE_MAX_MATCHES]; + unsigned int i; - assert(ndirectives > 0); + assert (ndirectives > 0); - for (i = 0; i != ndirectives; ++i) { - assert(directives[i].cre); - if (!regexec(directives[i].cre, line, RE_MAX_MATCHES, match, 0)) - return (*directives[i].handler) (conf, line, match); - } + for (i = 0; i != ndirectives; ++i) + { + assert (directives[i].cre); + if (!regexec (directives[i].cre, line, RE_MAX_MATCHES, match, 0)) + return (*directives[i].handler) (conf, line, match); + } - return -1; + return -1; } /* * Parse the previously opened configuration stream. */ int -config_parse(struct config_s *conf, FILE * f) +config_parse (struct config_s *conf, FILE * f) { - char buffer[1024]; /* 1KB lines should be plenty */ - unsigned long lineno = 1; + char buffer[1024]; /* 1KB lines should be plenty */ + unsigned long lineno = 1; - while (fgets(buffer, sizeof(buffer), f)) { - if (check_match(conf, buffer)) { - printf("Syntax error on line %ld\n", lineno); - return 1; - } - ++lineno; - } - return 0; + while (fgets (buffer, sizeof (buffer), f)) + { + if (check_match (conf, buffer)) + { + printf ("Syntax error on line %ld\n", lineno); + return 1; + } + ++lineno; + } + return 0; } /*********************************************************************** @@ -313,78 +312,79 @@ config_parse(struct config_s *conf, FILE * f) ***********************************************************************/ static char * -get_string_arg(const char *line, regmatch_t * match) +get_string_arg (const char *line, regmatch_t * match) { - char *p; - const unsigned int len = match->rm_eo - match->rm_so; + char *p; + const unsigned int len = match->rm_eo - match->rm_so; - assert(line); - assert(len > 0); + assert (line); + assert (len > 0); - p = safemalloc(len + 1); - if (!p) - return NULL; + p = safemalloc (len + 1); + if (!p) + return NULL; - memcpy(p, line + match->rm_so, len); - p[len] = '\0'; - return p; + memcpy (p, line + match->rm_so, len); + p[len] = '\0'; + return p; } static int -set_string_arg(char **var, const char *line, regmatch_t * match) +set_string_arg (char **var, const char *line, regmatch_t * match) { - char *arg = get_string_arg(line, match); + char *arg = get_string_arg (line, match); - if (!arg) - return -1; - *var = safestrdup(arg); - safefree(arg); - return *var ? 0 : -1; + if (!arg) + return -1; + *var = safestrdup (arg); + safefree (arg); + return *var ? 0 : -1; } static int -get_bool_arg(const char *line, regmatch_t * match) +get_bool_arg (const char *line, regmatch_t * match) { - const char *p = line + match->rm_so; + const char *p = line + match->rm_so; - assert(line); - assert(match && match->rm_so != -1); + assert (line); + assert (match && match->rm_so != -1); - /* "y"es or o"n" map as true, otherwise it's false. */ - if (tolower(p[0]) == 'y' || tolower(p[1]) == 'n') - return 1; - else - return 0; + /* "y"es or o"n" map as true, otherwise it's false. */ + if (tolower (p[0]) == 'y' || tolower (p[1]) == 'n') + return 1; + else + return 0; } static int -set_bool_arg(unsigned int *var, const char *line, regmatch_t * match) +set_bool_arg (unsigned int *var, const char *line, regmatch_t * match) { - assert(var); - assert(line); - assert(match && match->rm_so != -1); + assert (var); + assert (line); + assert (match && match->rm_so != -1); - *var = get_bool_arg(line, match); - return 0; + *var = get_bool_arg (line, match); + return 0; } static inline long int -get_int_arg(const char *line, regmatch_t * match) +get_int_arg (const char *line, regmatch_t * match) { - assert(line); - assert(match && match->rm_so != -1); + assert (line); + assert (match && match->rm_so != -1); - return strtol(line + match->rm_so, NULL, 0); + return strtol (line + match->rm_so, NULL, 0); } + static int -set_int_arg(int long *var, const char *line, regmatch_t * match) +set_int_arg (int long *var, const char *line, regmatch_t * match) { - assert(var); - assert(line); - assert(match); + assert (var); + assert (line); + assert (match); - *var = get_int_arg(line, match); - return 0; + *var = get_int_arg (line, match); + return 0; } /*********************************************************************** @@ -406,392 +406,404 @@ set_int_arg(int long *var, const char *line, regmatch_t * match) ***********************************************************************/ static -HANDLE_FUNC(handle_logfile) +HANDLE_FUNC (handle_logfile) { - return set_string_arg(&conf->logf_name, line, &match[2]); + return set_string_arg (&conf->logf_name, line, &match[2]); } static -HANDLE_FUNC(handle_pidfile) +HANDLE_FUNC (handle_pidfile) { - return set_string_arg(&conf->pidpath, line, &match[2]); + return set_string_arg (&conf->pidpath, line, &match[2]); } static -HANDLE_FUNC(handle_anonymous) +HANDLE_FUNC (handle_anonymous) { - char *arg = get_string_arg(line, &match[2]); + char *arg = get_string_arg (line, &match[2]); - if (!arg) - return -1; + if (!arg) + return -1; - anonymous_insert(arg); - safefree(arg); - return 0; + anonymous_insert (arg); + safefree (arg); + return 0; } static -HANDLE_FUNC(handle_viaproxyname) +HANDLE_FUNC (handle_viaproxyname) { - int r = set_string_arg(&conf->via_proxy_name, line, &match[2]); + int r = set_string_arg (&conf->via_proxy_name, line, &match[2]); - if (r) - return r; - log_message(LOG_INFO, - "Setting \"Via\" header proxy to %s", conf->via_proxy_name); - return 0; + if (r) + return r; + log_message (LOG_INFO, + "Setting \"Via\" header proxy to %s", conf->via_proxy_name); + return 0; } static -HANDLE_FUNC(handle_defaulterrorfile) +HANDLE_FUNC (handle_defaulterrorfile) { - return set_string_arg(&conf->errorpage_undef, line, &match[2]); + return set_string_arg (&conf->errorpage_undef, line, &match[2]); } static -HANDLE_FUNC(handle_statfile) +HANDLE_FUNC (handle_statfile) { - return set_string_arg(&conf->statpage, line, &match[2]); + return set_string_arg (&conf->statpage, line, &match[2]); } static -HANDLE_FUNC(handle_stathost) +HANDLE_FUNC (handle_stathost) { - int r = set_string_arg(&conf->stathost, line, &match[2]); + int r = set_string_arg (&conf->stathost, line, &match[2]); - if (r) - return r; - log_message(LOG_INFO, "Stathost set to \"%s\"", conf->stathost); - return 0; + if (r) + return r; + log_message (LOG_INFO, "Stathost set to \"%s\"", conf->stathost); + return 0; } static -HANDLE_FUNC(handle_xtinyproxy) +HANDLE_FUNC (handle_xtinyproxy) { #ifdef XTINYPROXY_ENABLE - return set_string_arg(&conf->my_domain, line, &match[2]); + return set_string_arg (&conf->my_domain, line, &match[2]); #else - fprintf(stderr, - "XTinyproxy NOT Enabled! Recompile with --enable-xtinyproxy\n"); - return 1; + fprintf (stderr, + "XTinyproxy NOT Enabled! Recompile with --enable-xtinyproxy\n"); + return 1; #endif } static -HANDLE_FUNC(handle_syslog) +HANDLE_FUNC (handle_syslog) { #ifdef HAVE_SYSLOG_H - return set_bool_arg(&conf->syslog, line, &match[2]); + return set_bool_arg (&conf->syslog, line, &match[2]); #else - fprintf(stderr, "Syslog support not compiled in executable.\n"); - return 1; + fprintf (stderr, "Syslog support not compiled in executable.\n"); + return 1; #endif } static -HANDLE_FUNC(handle_bindsame) +HANDLE_FUNC (handle_bindsame) { - int r = set_bool_arg(&conf->bindsame, line, &match[2]); + int r = set_bool_arg (&conf->bindsame, line, &match[2]); - if (r) - return r; - log_message(LOG_INFO, "Binding outgoing connection to incoming IP"); - return 0; + if (r) + return r; + log_message (LOG_INFO, "Binding outgoing connection to incoming IP"); + return 0; } static -HANDLE_FUNC(handle_port) +HANDLE_FUNC (handle_port) { - return set_int_arg((long int *)&conf->port, line, &match[2]); + return set_int_arg ((long int *) &conf->port, line, &match[2]); } static -HANDLE_FUNC(handle_maxclients) +HANDLE_FUNC (handle_maxclients) { - child_configure(CHILD_MAXCLIENTS, get_int_arg(line, &match[2])); - return 0; + child_configure (CHILD_MAXCLIENTS, get_int_arg (line, &match[2])); + return 0; } static -HANDLE_FUNC(handle_maxspareservers) +HANDLE_FUNC (handle_maxspareservers) { - child_configure(CHILD_MAXSPARESERVERS, get_int_arg(line, &match[2])); - return 0; + child_configure (CHILD_MAXSPARESERVERS, get_int_arg (line, &match[2])); + return 0; } static -HANDLE_FUNC(handle_minspareservers) +HANDLE_FUNC (handle_minspareservers) { - child_configure(CHILD_MINSPARESERVERS, get_int_arg(line, &match[2])); - return 0; + child_configure (CHILD_MINSPARESERVERS, get_int_arg (line, &match[2])); + return 0; } static -HANDLE_FUNC(handle_startservers) +HANDLE_FUNC (handle_startservers) { - child_configure(CHILD_STARTSERVERS, get_int_arg(line, &match[2])); - return 0; + child_configure (CHILD_STARTSERVERS, get_int_arg (line, &match[2])); + return 0; } static -HANDLE_FUNC(handle_maxrequestsperchild) +HANDLE_FUNC (handle_maxrequestsperchild) { - child_configure(CHILD_MAXREQUESTSPERCHILD, - get_int_arg(line, &match[2])); - return 0; + child_configure (CHILD_MAXREQUESTSPERCHILD, get_int_arg (line, &match[2])); + return 0; } static -HANDLE_FUNC(handle_timeout) +HANDLE_FUNC (handle_timeout) { - return set_int_arg((long int *)&conf->idletimeout, line, &match[2]); + return set_int_arg ((long int *) &conf->idletimeout, line, &match[2]); } static -HANDLE_FUNC(handle_connectport) +HANDLE_FUNC (handle_connectport) { - add_connect_port_allowed(get_int_arg(line, &match[2])); - return 0; + add_connect_port_allowed (get_int_arg (line, &match[2])); + return 0; } static -HANDLE_FUNC(handle_user) +HANDLE_FUNC (handle_user) { - return set_string_arg(&conf->user, line, &match[2]); + return set_string_arg (&conf->user, line, &match[2]); } static -HANDLE_FUNC(handle_group) +HANDLE_FUNC (handle_group) { - return set_string_arg(&conf->group, line, &match[2]); + return set_string_arg (&conf->group, line, &match[2]); } static -HANDLE_FUNC(handle_allow) +HANDLE_FUNC (handle_allow) { - char *arg = get_string_arg(line, &match[2]); + char *arg = get_string_arg (line, &match[2]); - insert_acl(arg, ACL_ALLOW); - safefree(arg); - return 0; + insert_acl (arg, ACL_ALLOW); + safefree (arg); + return 0; } static -HANDLE_FUNC(handle_deny) +HANDLE_FUNC (handle_deny) { - char *arg = get_string_arg(line, &match[2]); + char *arg = get_string_arg (line, &match[2]); - insert_acl(arg, ACL_DENY); - safefree(arg); - return 0; + insert_acl (arg, ACL_DENY); + safefree (arg); + return 0; } static -HANDLE_FUNC(handle_bind) +HANDLE_FUNC (handle_bind) { #ifndef TRANSPARENT_PROXY - int r = set_string_arg(&conf->bind_address, line, &match[2]); + int r = set_string_arg (&conf->bind_address, line, &match[2]); - if (r) - return r; - log_message(LOG_INFO, - "Outgoing connections bound to IP %s", conf->bind_address); - return 0; + if (r) + return r; + log_message (LOG_INFO, + "Outgoing connections bound to IP %s", conf->bind_address); + return 0; #else - fprintf(stderr, - "\"Bind\" cannot be used with transparent support enabled.\n"); - return 1; + fprintf (stderr, + "\"Bind\" cannot be used with transparent support enabled.\n"); + return 1; #endif } static -HANDLE_FUNC(handle_listen) +HANDLE_FUNC (handle_listen) { - int r = set_string_arg(&conf->ipAddr, line, &match[2]); + int r = set_string_arg (&conf->ipAddr, line, &match[2]); - if (r) - return r; - log_message(LOG_INFO, "Listing on IP %s", conf->ipAddr); - return 0; + if (r) + return r; + log_message (LOG_INFO, "Listing on IP %s", conf->ipAddr); + return 0; } static -HANDLE_FUNC(handle_errorfile) +HANDLE_FUNC (handle_errorfile) { - /* - * Because an integer is defined as ((0x)?[[:digit:]]+) _two_ - * match places are used. match[2] matches the full digit - * string, while match[3] matches only the "0x" part if - * present. This is why the "string" is located at - * match[4] (rather than the more intuitive match[3]. - */ - long int err = get_int_arg(line, &match[2]); - char *page = get_string_arg(line, &match[4]); + /* + * Because an integer is defined as ((0x)?[[:digit:]]+) _two_ + * match places are used. match[2] matches the full digit + * string, while match[3] matches only the "0x" part if + * present. This is why the "string" is located at + * match[4] (rather than the more intuitive match[3]. + */ + long int err = get_int_arg (line, &match[2]); + char *page = get_string_arg (line, &match[4]); - add_new_errorpage(page, err); - safefree(page); - return 0; + add_new_errorpage (page, err); + safefree (page); + return 0; } /* * Log level's strings. */ -struct log_levels_s { - const char *string; - int level; +struct log_levels_s +{ + const char *string; + int level; }; static struct log_levels_s log_levels[] = { - {"critical", LOG_CRIT}, - {"error", LOG_ERR}, - {"warning", LOG_WARNING}, - {"notice", LOG_NOTICE}, - {"connect", LOG_CONN}, - {"info", LOG_INFO} + {"critical", LOG_CRIT}, + {"error", LOG_ERR}, + {"warning", LOG_WARNING}, + {"notice", LOG_NOTICE}, + {"connect", LOG_CONN}, + {"info", LOG_INFO} }; static -HANDLE_FUNC(handle_loglevel) +HANDLE_FUNC (handle_loglevel) { - static const unsigned int nlevels = - sizeof(log_levels) / sizeof(log_levels[0]); - unsigned int i; + static const unsigned int nlevels = + sizeof (log_levels) / sizeof (log_levels[0]); + unsigned int i; - char *arg = get_string_arg(line, &match[2]); + char *arg = get_string_arg (line, &match[2]); - for (i = 0; i != nlevels; ++i) { - if (!strcasecmp(arg, log_levels[i].string)) { - set_log_level(log_levels[i].level); - safefree(arg); - return 0; - } - } + for (i = 0; i != nlevels; ++i) + { + if (!strcasecmp (arg, log_levels[i].string)) + { + set_log_level (log_levels[i].level); + safefree (arg); + return 0; + } + } - safefree(arg); - return -1; + safefree (arg); + return -1; } #ifdef FILTER_ENABLE static -HANDLE_FUNC(handle_filter) +HANDLE_FUNC (handle_filter) { - return set_string_arg(&conf->filter, line, &match[2]); + return set_string_arg (&conf->filter, line, &match[2]); } static -HANDLE_FUNC(handle_filterurls) +HANDLE_FUNC (handle_filterurls) { - return set_bool_arg(&conf->filter_url, line, &match[2]); + return set_bool_arg (&conf->filter_url, line, &match[2]); } static -HANDLE_FUNC(handle_filterextended) +HANDLE_FUNC (handle_filterextended) { - return set_bool_arg(&conf->filter_extended, line, &match[2]); + return set_bool_arg (&conf->filter_extended, line, &match[2]); } static -HANDLE_FUNC(handle_filterdefaultdeny) +HANDLE_FUNC (handle_filterdefaultdeny) { - assert(match[2].rm_so != -1); + assert (match[2].rm_so != -1); - if (get_bool_arg(line, &match[2])) - filter_set_default_policy(FILTER_DEFAULT_DENY); - return 0; + if (get_bool_arg (line, &match[2])) + filter_set_default_policy (FILTER_DEFAULT_DENY); + return 0; } static -HANDLE_FUNC(handle_filtercasesensitive) +HANDLE_FUNC (handle_filtercasesensitive) { - return set_bool_arg(&conf->filter_casesensitive, line, &match[2]); + return set_bool_arg (&conf->filter_casesensitive, line, &match[2]); } #endif #ifdef REVERSE_SUPPORT static -HANDLE_FUNC(handle_reverseonly) +HANDLE_FUNC (handle_reverseonly) { - return set_bool_arg(&conf->reverseonly, line, &match[2]); + return set_bool_arg (&conf->reverseonly, line, &match[2]); } static -HANDLE_FUNC(handle_reversemagic) +HANDLE_FUNC (handle_reversemagic) { - return set_bool_arg(&conf->reversemagic, line, &match[2]); + return set_bool_arg (&conf->reversemagic, line, &match[2]); } static -HANDLE_FUNC(handle_reversebaseurl) +HANDLE_FUNC (handle_reversebaseurl) { - return set_string_arg(&conf->reversebaseurl, line, &match[2]); + return set_string_arg (&conf->reversebaseurl, line, &match[2]); } static -HANDLE_FUNC(handle_reversepath) +HANDLE_FUNC (handle_reversepath) { - /* - * The second string argument is optional. - */ - char *arg1, *arg2; + /* + * The second string argument is optional. + */ + char *arg1, *arg2; - arg1 = get_string_arg(line, &match[2]); - if (!arg1) - return -1; + arg1 = get_string_arg (line, &match[2]); + if (!arg1) + return -1; - if (match[3].rm_so != -1) { - arg2 = get_string_arg(line, &match[3]); - if (!arg2) { - safefree(arg1); - return -1; - } - reversepath_add(arg1, arg2); - safefree(arg1); - safefree(arg2); - } else { - reversepath_add(NULL, arg1); - safefree(arg1); - } - return 0; + if (match[3].rm_so != -1) + { + arg2 = get_string_arg (line, &match[3]); + if (!arg2) + { + safefree (arg1); + return -1; + } + reversepath_add (arg1, arg2); + safefree (arg1); + safefree (arg2); + } + else + { + reversepath_add (NULL, arg1); + safefree (arg1); + } + return 0; } #endif #ifdef UPSTREAM_SUPPORT static -HANDLE_FUNC(handle_upstream) +HANDLE_FUNC (handle_upstream) { - char *ip; - int port; - char *domain; + char *ip; + int port; + char *domain; - ip = get_string_arg(line, &match[2]); - if (!ip) return -1; - port = get_int_arg(line, &match[7]); + ip = get_string_arg (line, &match[2]); + if (!ip) + return -1; + port = get_int_arg (line, &match[7]); - if (match[9].rm_so != -1) { - domain = get_string_arg(line, &match[9]); - if (domain) { - upstream_add(ip, port, domain); - safefree(domain); - } - } else { - upstream_add(ip, port, NULL); - } + if (match[9].rm_so != -1) + { + domain = get_string_arg (line, &match[9]); + if (domain) + { + upstream_add (ip, port, domain); + safefree (domain); + } + } + else + { + upstream_add (ip, port, NULL); + } - safefree(ip); + safefree (ip); - return 0; + return 0; } static -HANDLE_FUNC(handle_upstream_no) +HANDLE_FUNC (handle_upstream_no) { - char *domain; + char *domain; - domain = get_string_arg(line, &match[2]); - if (!domain) return -1; + domain = get_string_arg (line, &match[2]); + if (!domain) + return -1; - upstream_add(NULL, 0, domain); - safefree(domain); + upstream_add (NULL, 0, domain); + safefree (domain); - return 0; + return 0; } #endif diff --git a/src/conffile.h b/src/conffile.h index 6393141..3c1b94b 100644 --- a/src/conffile.h +++ b/src/conffile.h @@ -21,7 +21,7 @@ #ifndef TINYPROXY_CONFFILE_H #define TINYPROXY_CONFFILE_H -extern int config_compile(void); -extern int config_parse(struct config_s *conf, FILE * f); +extern int config_compile (void); +extern int config_parse (struct config_s *conf, FILE * f); #endif diff --git a/src/conns.c b/src/conns.c index 860d7c3..6c04383 100644 --- a/src/conns.c +++ b/src/conns.c @@ -31,118 +31,118 @@ #include "stats.h" struct conn_s * -initialize_conn(int client_fd, const char *ipaddr, const char *string_addr, - const char *sock_ipaddr) +initialize_conn (int client_fd, const char *ipaddr, const char *string_addr, + const char *sock_ipaddr) { - struct conn_s *connptr; - struct buffer_s *cbuffer, *sbuffer; + struct conn_s *connptr; + struct buffer_s *cbuffer, *sbuffer; - assert(client_fd >= 0); + assert (client_fd >= 0); - /* - * Allocate the memory for all the internal components - */ - cbuffer = new_buffer(); - sbuffer = new_buffer(); + /* + * Allocate the memory for all the internal components + */ + cbuffer = new_buffer (); + sbuffer = new_buffer (); - if (!cbuffer || !sbuffer) - goto error_exit; + if (!cbuffer || !sbuffer) + goto error_exit; - /* - * Allocate the space for the conn_s structure itself. - */ - connptr = safemalloc(sizeof(struct conn_s)); - if (!connptr) - goto error_exit; + /* + * Allocate the space for the conn_s structure itself. + */ + connptr = safemalloc (sizeof (struct conn_s)); + if (!connptr) + goto error_exit; - connptr->client_fd = client_fd; - connptr->server_fd = -1; + connptr->client_fd = client_fd; + connptr->server_fd = -1; - connptr->cbuffer = cbuffer; - connptr->sbuffer = sbuffer; + connptr->cbuffer = cbuffer; + connptr->sbuffer = sbuffer; - connptr->request_line = NULL; + connptr->request_line = NULL; - /* These store any error strings */ - connptr->error_variables = NULL; - connptr->error_string = NULL; - connptr->error_number = -1; + /* These store any error strings */ + connptr->error_variables = NULL; + connptr->error_string = NULL; + connptr->error_number = -1; - connptr->connect_method = FALSE; - connptr->show_stats = FALSE; + connptr->connect_method = 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 */ - connptr->content_length.server = connptr->content_length.client = -1; + /* There is _no_ content length initially */ + connptr->content_length.server = connptr->content_length.client = -1; - connptr->server_ip_addr = sock_ipaddr ? safestrdup(sock_ipaddr) : 0; - connptr->client_ip_addr = safestrdup(ipaddr); - connptr->client_string_addr = safestrdup(string_addr); + connptr->server_ip_addr = sock_ipaddr ? safestrdup (sock_ipaddr) : 0; + connptr->client_ip_addr = safestrdup (ipaddr); + 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 - connptr->reversepath = NULL; + connptr->reversepath = NULL; #endif - return connptr; + return connptr; - error_exit: - /* - * If we got here, there was a problem allocating memory - */ - if (cbuffer) - delete_buffer(cbuffer); - if (sbuffer) - delete_buffer(sbuffer); +error_exit: + /* + * If we got here, there was a problem allocating memory + */ + if (cbuffer) + delete_buffer (cbuffer); + if (sbuffer) + delete_buffer (sbuffer); - return NULL; + return NULL; } void -destroy_conn(struct conn_s *connptr) +destroy_conn (struct conn_s *connptr) { - assert(connptr != NULL); - - if (connptr->client_fd != -1) - if (close(connptr->client_fd) < 0) - log_message(LOG_INFO, "Client (%d) close message: %s", - connptr->client_fd, strerror(errno)); - if (connptr->server_fd != -1) - if (close(connptr->server_fd) < 0) - log_message(LOG_INFO, "Server (%d) close message: %s", - connptr->server_fd, strerror(errno)); - - if (connptr->cbuffer) - delete_buffer(connptr->cbuffer); - if (connptr->sbuffer) - delete_buffer(connptr->sbuffer); - - if (connptr->request_line) - safefree(connptr->request_line); - - if (connptr->error_variables) - hashmap_delete(connptr->error_variables); - - if (connptr->error_string) - safefree(connptr->error_string); - - if (connptr->server_ip_addr) - safefree(connptr->server_ip_addr); - if (connptr->client_ip_addr) - safefree(connptr->client_ip_addr); - if (connptr->client_string_addr) - safefree(connptr->client_string_addr); + assert (connptr != NULL); + + if (connptr->client_fd != -1) + if (close (connptr->client_fd) < 0) + log_message (LOG_INFO, "Client (%d) close message: %s", + connptr->client_fd, strerror (errno)); + if (connptr->server_fd != -1) + if (close (connptr->server_fd) < 0) + log_message (LOG_INFO, "Server (%d) close message: %s", + connptr->server_fd, strerror (errno)); + + if (connptr->cbuffer) + delete_buffer (connptr->cbuffer); + if (connptr->sbuffer) + delete_buffer (connptr->sbuffer); + + if (connptr->request_line) + safefree (connptr->request_line); + + if (connptr->error_variables) + hashmap_delete (connptr->error_variables); + + if (connptr->error_string) + safefree (connptr->error_string); + + if (connptr->server_ip_addr) + safefree (connptr->server_ip_addr); + if (connptr->client_ip_addr) + safefree (connptr->client_ip_addr); + if (connptr->client_string_addr) + safefree (connptr->client_string_addr); #ifdef REVERSE_SUPPORT - if (connptr->reversepath) - safefree(connptr->reversepath); + if (connptr->reversepath) + safefree (connptr->reversepath); #endif - safefree(connptr); + safefree (connptr); - update_stats(STAT_CLOSE); + update_stats (STAT_CLOSE); } diff --git a/src/conns.h b/src/conns.h index 1e1bf45..6c2f365 100644 --- a/src/conns.h +++ b/src/conns.h @@ -27,73 +27,76 @@ /* * Connection Definition */ -struct conn_s { - int client_fd; - int server_fd; - - struct buffer_s *cbuffer; - struct buffer_s *sbuffer; - - /* The request line (first line) from the client */ - char *request_line; - - /* Booleans */ - unsigned int connect_method; - unsigned int show_stats; - - /* - * This structure stores key -> value mappings for substitution - * in the error HTML files. - */ - hashmap_t error_variables; - - int error_number; - char *error_string; - - /* A Content-Length value from the remote server */ - struct { - long int server; - long int client; - } content_length; - - /* - * Store the server's IP (for BindSame) - */ - char *server_ip_addr; - - /* - * Store the client's IP and hostname information - */ - char *client_ip_addr; - char *client_string_addr; - - /* - * Store the incoming request's HTTP protocol. - */ - struct { - unsigned int major; - unsigned int minor; - } protocol; +struct conn_s +{ + int client_fd; + int server_fd; + + struct buffer_s *cbuffer; + struct buffer_s *sbuffer; + + /* The request line (first line) from the client */ + char *request_line; + + /* Booleans */ + unsigned int connect_method; + unsigned int show_stats; + + /* + * This structure stores key -> value mappings for substitution + * in the error HTML files. + */ + hashmap_t error_variables; + + int error_number; + char *error_string; + + /* A Content-Length value from the remote server */ + struct + { + long int server; + long int client; + } content_length; + + /* + * Store the server's IP (for BindSame) + */ + char *server_ip_addr; + + /* + * Store the client's IP and hostname information + */ + char *client_ip_addr; + char *client_string_addr; + + /* + * Store the incoming request's HTTP protocol. + */ + struct + { + unsigned int major; + unsigned int minor; + } protocol; #ifdef REVERSE_SUPPORT - /* - * Place to store the current per-connection reverse proxy path - */ - char *reversepath; + /* + * Place to store the current per-connection reverse proxy path + */ + char *reversepath; #endif - /* - * Pointer to upstream proxy. - */ - struct upstream *upstream_proxy; + /* + * Pointer to upstream proxy. + */ + struct upstream *upstream_proxy; }; /* * Functions for the creation and destruction of a connection structure. */ -extern struct conn_s *initialize_conn(int client_fd, const char *ipaddr, - const char *string_addr, - const char *sock_ipaddr); -extern void destroy_conn(struct conn_s *connptr); +extern struct conn_s *initialize_conn (int client_fd, const char *ipaddr, + const char *string_addr, + const char *sock_ipaddr); +extern void destroy_conn (struct conn_s *connptr); #endif diff --git a/src/daemon.c b/src/daemon.c index f0b0aba..fc39b42 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -30,28 +30,28 @@ * program a daemon process. */ void -makedaemon(void) +makedaemon (void) { - if (fork() != 0) - exit(0); + if (fork () != 0) + exit (0); - setsid(); - set_signal_handler(SIGHUP, SIG_IGN); + setsid (); + set_signal_handler (SIGHUP, SIG_IGN); - if (fork() != 0) - exit(0); + if (fork () != 0) + exit (0); - chdir("/"); - umask(0177); + chdir ("/"); + umask (0177); #if NDEBUG - /* - * When not in debugging mode, close the standard file - * descriptors. - */ - close(0); - close(1); - close(2); + /* + * When not in debugging mode, close the standard file + * descriptors. + */ + close (0); + close (1); + close (2); #endif } @@ -60,25 +60,28 @@ makedaemon(void) * to handle signals sent to the process. */ 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; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - if (signo == SIGALRM) { + act.sa_handler = func; + sigemptyset (&act.sa_mask); + act.sa_flags = 0; + if (signo == SIGALRM) + { #ifdef SA_INTERRUPT - act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */ + act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */ #endif - } else { + } + else + { #ifdef SA_RESTART - act.sa_flags |= SA_RESTART; /* SVR4, 4.4BSD */ + act.sa_flags |= SA_RESTART; /* SVR4, 4.4BSD */ #endif - } + } - if (sigaction(signo, &act, &oact) < 0) - return SIG_ERR; + if (sigaction (signo, &act, &oact) < 0) + return SIG_ERR; - return oact.sa_handler; + return oact.sa_handler; } diff --git a/src/daemon.h b/src/daemon.h index e6d33b1..63a679e 100644 --- a/src/daemon.h +++ b/src/daemon.h @@ -26,11 +26,11 @@ typedef void signal_func (int); /* * 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 */ -extern void makedaemon(void); +extern void makedaemon (void); #endif diff --git a/src/filter.c b/src/filter.c index 81d274b..06346c3 100644 --- a/src/filter.c +++ b/src/filter.c @@ -33,10 +33,11 @@ static int err; -struct filter_list { - struct filter_list *next; - char *pat; - regex_t *cpat; +struct filter_list +{ + struct filter_list *next; + char *pat; + regex_t *cpat; }; 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 */ void -filter_init(void) +filter_init (void) { - FILE *fd; - struct filter_list *p; - char buf[FILTER_BUFFER_LEN]; - char *s; - int cflags; - - if (!fl && !already_init) { - fd = fopen(config.filter, "r"); - if (fd) { - p = NULL; - - cflags = REG_NEWLINE | REG_NOSUB; - if (config.filter_extended) - cflags |= REG_EXTENDED; - if (!config.filter_casesensitive) - cflags |= REG_ICASE; - - while (fgets(buf, FILTER_BUFFER_LEN, fd)) { - /* - * Remove any trailing white space and - * comments. - */ - s = buf; - while (*s) { - if (isspace((unsigned char)*s)) - break; - if (*s == '#') { - /* - * If the '#' char is preceeded by - * an escape, it's not a comment - * string. - */ - if (s == buf - || *(s - 1) != '\\') - break; - } - ++s; - } - *s = '\0'; - - /* skip leading whitespace */ - s = buf; - while (*s && isspace((unsigned char)*s)) - s++; - - /* skip blank lines and comments */ - if (*s == '\0') - continue; - - if (!p) /* head of list */ - fl = p = - safecalloc(1, - sizeof(struct - filter_list)); - else { /* next entry */ - p->next = - safecalloc(1, - sizeof(struct - filter_list)); - p = p->next; - } - - p->pat = safestrdup(s); - p->cpat = safemalloc(sizeof(regex_t)); - if ((err = - regcomp(p->cpat, p->pat, cflags)) != 0) { - fprintf(stderr, "Bad regex in %s: %s\n", - config.filter, p->pat); - exit(EX_DATAERR); - } - } - if (ferror(fd)) { - perror("fgets"); - exit(EX_DATAERR); - } - fclose(fd); - - already_init = 1; - } - } + FILE *fd; + struct filter_list *p; + char buf[FILTER_BUFFER_LEN]; + char *s; + int cflags; + + if (!fl && !already_init) + { + fd = fopen (config.filter, "r"); + if (fd) + { + p = NULL; + + cflags = REG_NEWLINE | REG_NOSUB; + if (config.filter_extended) + cflags |= REG_EXTENDED; + if (!config.filter_casesensitive) + cflags |= REG_ICASE; + + while (fgets (buf, FILTER_BUFFER_LEN, fd)) + { + /* + * Remove any trailing white space and + * comments. + */ + s = buf; + while (*s) + { + if (isspace ((unsigned char) *s)) + break; + if (*s == '#') + { + /* + * If the '#' char is preceeded by + * an escape, it's not a comment + * string. + */ + if (s == buf || *(s - 1) != '\\') + break; + } + ++s; + } + *s = '\0'; + + /* skip leading whitespace */ + s = buf; + while (*s && isspace ((unsigned char) *s)) + s++; + + /* skip blank lines and comments */ + if (*s == '\0') + continue; + + if (!p) /* head of list */ + fl = p = safecalloc (1, sizeof (struct filter_list)); + else + { /* next entry */ + p->next = safecalloc (1, sizeof (struct filter_list)); + p = p->next; + } + + p->pat = safestrdup (s); + p->cpat = safemalloc (sizeof (regex_t)); + if ((err = regcomp (p->cpat, p->pat, cflags)) != 0) + { + fprintf (stderr, "Bad regex in %s: %s\n", + config.filter, p->pat); + exit (EX_DATAERR); + } + } + if (ferror (fd)) + { + perror ("fgets"); + exit (EX_DATAERR); + } + fclose (fd); + + already_init = 1; + } + } } /* unlink the list */ void -filter_destroy(void) +filter_destroy (void) { - struct filter_list *p, *q; - - if (already_init) { - for (p = q = fl; p; p = q) { - regfree(p->cpat); - safefree(p->cpat); - safefree(p->pat); - q = p->next; - safefree(p); - } - fl = NULL; - already_init = 0; - } + struct filter_list *p, *q; + + if (already_init) + { + for (p = q = fl; p; p = q) + { + regfree (p->cpat); + safefree (p->cpat); + safefree (p->pat); + q = p->next; + safefree (p); + } + fl = NULL; + already_init = 0; + } } /* Return 0 to allow, non-zero to block */ int -filter_domain(const char *host) +filter_domain (const char *host) { - struct filter_list *p; - int result; - - if (!fl || !already_init) - goto COMMON_EXIT; - - for (p = fl; p; p = p->next) { - result = - regexec(p->cpat, host, (size_t) 0, (regmatch_t *) 0, 0); - - if (result == 0) { - if (default_policy == FILTER_DEFAULT_ALLOW) - return 1; - else - return 0; - } - } - - COMMON_EXIT: - if (default_policy == FILTER_DEFAULT_ALLOW) - return 0; - else - return 1; + struct filter_list *p; + int result; + + if (!fl || !already_init) + goto COMMON_EXIT; + + for (p = fl; p; p = p->next) + { + result = regexec (p->cpat, host, (size_t) 0, (regmatch_t *) 0, 0); + + if (result == 0) + { + if (default_policy == FILTER_DEFAULT_ALLOW) + return 1; + else + return 0; + } + } + +COMMON_EXIT: + if (default_policy == FILTER_DEFAULT_ALLOW) + return 0; + else + return 1; } /* returns 0 to allow, non-zero to block */ int -filter_url(const char *url) +filter_url (const char *url) { - struct filter_list *p; - int result; - - if (!fl || !already_init) - goto COMMON_EXIT; - - for (p = fl; p; p = p->next) { - result = regexec(p->cpat, url, (size_t) 0, (regmatch_t *) 0, 0); - - if (result == 0) { - if (default_policy == FILTER_DEFAULT_ALLOW) - return 1; - else - return 0; - } - } - - COMMON_EXIT: - if (default_policy == FILTER_DEFAULT_ALLOW) - return 0; - else - return 1; + struct filter_list *p; + int result; + + if (!fl || !already_init) + goto COMMON_EXIT; + + for (p = fl; p; p = p->next) + { + result = regexec (p->cpat, url, (size_t) 0, (regmatch_t *) 0, 0); + + if (result == 0) + { + if (default_policy == FILTER_DEFAULT_ALLOW) + return 1; + else + return 0; + } + } + +COMMON_EXIT: + if (default_policy == FILTER_DEFAULT_ALLOW) + return 0; + else + return 1; } /* * Set the default filtering policy */ void -filter_set_default_policy(filter_policy_t policy) +filter_set_default_policy (filter_policy_t policy) { - default_policy = policy; + default_policy = policy; } diff --git a/src/filter.h b/src/filter.h index 7c5fcad..17974a6 100644 --- a/src/filter.h +++ b/src/filter.h @@ -21,16 +21,17 @@ #ifndef _TINYPROXY_FILTER_H_ #define _TINYPROXY_FILTER_H_ -typedef enum { - FILTER_DEFAULT_ALLOW, - FILTER_DEFAULT_DENY, +typedef enum +{ + FILTER_DEFAULT_ALLOW, + FILTER_DEFAULT_DENY, } filter_policy_t; -extern void filter_init(void); -extern void filter_destroy(void); -extern int filter_domain(const char *host); -extern int filter_url(const char *url); +extern void filter_init (void); +extern void filter_destroy (void); +extern int filter_domain (const char *host); +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 diff --git a/src/hashmap.c b/src/hashmap.c index 292c006..764c9a6 100644 --- a/src/hashmap.c +++ b/src/hashmap.c @@ -37,23 +37,26 @@ * internal use. It stores the number of buckets the hashmap was created * with. */ -struct hashentry_s { - char *key; - void *data; - size_t len; +struct hashentry_s +{ + char *key; + void *data; + size_t len; - struct hashentry_s *prev, *next; + struct hashentry_s *prev, *next; }; -struct hashbucket_s { - struct hashentry_s *head, *tail; +struct hashbucket_s +{ + struct hashentry_s *head, *tail; }; -struct hashmap_s { - unsigned int size; - hashmap_iter end_iterator; +struct hashmap_s +{ + 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. */ 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) - return -EINVAL; - if (size == 0) - return -ERANGE; + if (key == NULL) + return -EINVAL; + if (size == 0) + return -ERANGE; - for (hash = tolower(*key++); *key != '\0'; key++) { - uint32_t bit = (hash & 1) ? (1 << (sizeof(uint32_t) - 1)) : 0; + for (hash = tolower (*key++); *key != '\0'; key++) + { + 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 */ - return hash % size; + /* Keep the hash within the table limits */ + 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. */ hashmap_t -hashmap_create(unsigned int nbuckets) +hashmap_create (unsigned int nbuckets) { - struct hashmap_s *ptr; + struct hashmap_s *ptr; - if (nbuckets == 0) - return NULL; + if (nbuckets == 0) + return NULL; - ptr = safecalloc(1, sizeof(struct hashmap_s)); - if (!ptr) - return NULL; + ptr = safecalloc (1, sizeof (struct hashmap_s)); + if (!ptr) + return NULL; - ptr->size = nbuckets; - ptr->buckets = safecalloc(nbuckets, sizeof(struct hashbucket_s)); - if (!ptr->buckets) { - safefree(ptr); - return NULL; - } + ptr->size = nbuckets; + ptr->buckets = safecalloc (nbuckets, sizeof (struct hashbucket_s)); + if (!ptr->buckets) + { + safefree (ptr); + return NULL; + } - /* This points to "one" past the end of the hashmap. */ - ptr->end_iterator = 0; + /* This points to "one" past the end of the hashmap. */ + 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 */ static inline int -delete_hashbucket(struct hashbucket_s *bucket) +delete_hashbucket (struct hashbucket_s *bucket) { - struct hashentry_s *nextptr; - struct hashentry_s *ptr; + struct hashentry_s *nextptr; + struct hashentry_s *ptr; - if (bucket == NULL || bucket->head == NULL) - return -EINVAL; + if (bucket == NULL || bucket->head == NULL) + return -EINVAL; - ptr = bucket->head; - while (ptr) { - nextptr = ptr->next; + ptr = bucket->head; + while (ptr) + { + nextptr = ptr->next; - safefree(ptr->key); - safefree(ptr->data); - safefree(ptr); + safefree (ptr->key); + safefree (ptr->data); + 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 */ int -hashmap_delete(hashmap_t map) +hashmap_delete (hashmap_t map) { - unsigned int i; + unsigned int i; - if (map == NULL) - return -EINVAL; + if (map == NULL) + return -EINVAL; - for (i = 0; i != map->size; i++) { - if (map->buckets[i].head != NULL) { - delete_hashbucket(&map->buckets[i]); - } - } + for (i = 0; i != map->size; i++) + { + if (map->buckets[i].head != NULL) + { + delete_hashbucket (&map->buckets[i]); + } + } - safefree(map->buckets); - safefree(map); + safefree (map->buckets); + safefree (map); - return 0; + return 0; } /* @@ -186,67 +194,69 @@ hashmap_delete(hashmap_t map) * negative number if there are errors */ 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; - int hash; - char *key_copy; - void *data_copy; - - assert(map != NULL); - assert(key != NULL); - assert(data != NULL); - assert(len > 0); - - if (map == NULL || key == NULL) - return -EINVAL; - if (!data || len < 1) - return -ERANGE; - - hash = hashfunc(key, map->size); - if (hash < 0) - return hash; - - /* - * First make copies of the key and data in case there is a memory - * problem later. - */ - key_copy = safestrdup(key); - if (!key_copy) - return -ENOMEM; - - data_copy = safemalloc(len); - if (!data_copy) { - safefree(key_copy); - return -ENOMEM; - } - memcpy(data_copy, data, len); - - ptr = safemalloc(sizeof(struct hashentry_s)); - if (!ptr) { - safefree(key_copy); - safefree(data_copy); - return -ENOMEM; - } - - ptr->key = key_copy; - ptr->data = data_copy; - ptr->len = len; - - /* - * Now add the entry to the end of the bucket chain. - */ - ptr->next = NULL; - ptr->prev = map->buckets[hash].tail; - if (map->buckets[hash].tail) - map->buckets[hash].tail->next = ptr; - - map->buckets[hash].tail = ptr; - if (!map->buckets[hash].head) - map->buckets[hash].head = ptr; - - map->end_iterator++; - return 0; + struct hashentry_s *ptr; + int hash; + char *key_copy; + void *data_copy; + + assert (map != NULL); + assert (key != NULL); + assert (data != NULL); + assert (len > 0); + + if (map == NULL || key == NULL) + return -EINVAL; + if (!data || len < 1) + return -ERANGE; + + hash = hashfunc (key, map->size); + if (hash < 0) + return hash; + + /* + * First make copies of the key and data in case there is a memory + * problem later. + */ + key_copy = safestrdup (key); + if (!key_copy) + return -ENOMEM; + + data_copy = safemalloc (len); + if (!data_copy) + { + safefree (key_copy); + return -ENOMEM; + } + memcpy (data_copy, data, len); + + ptr = safemalloc (sizeof (struct hashentry_s)); + if (!ptr) + { + safefree (key_copy); + safefree (data_copy); + return -ENOMEM; + } + + ptr->key = key_copy; + ptr->data = data_copy; + ptr->len = len; + + /* + * Now add the entry to the end of the bucket chain. + */ + ptr->next = NULL; + ptr->prev = map->buckets[hash].tail; + if (map->buckets[hash].tail) + map->buckets[hash].tail->next = ptr; + + map->buckets[hash].tail = ptr; + if (!map->buckets[hash].head) + map->buckets[hash].head = ptr; + + map->end_iterator++; + 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. */ hashmap_iter -hashmap_first(hashmap_t map) +hashmap_first (hashmap_t map) { - assert(map != NULL); + assert (map != NULL); - if (!map) - return -EINVAL; + if (!map) + return -EINVAL; - if (map->end_iterator == 0) - return -1; - else - return 0; + if (map->end_iterator == 0) + return -1; + else + return 0; } /* @@ -275,18 +285,18 @@ hashmap_first(hashmap_t map) * 0 otherwise */ int -hashmap_is_end(hashmap_t map, hashmap_iter iter) +hashmap_is_end (hashmap_t map, hashmap_iter iter) { - assert(map != NULL); - assert(iter >= 0); + assert (map != NULL); + assert (iter >= 0); - if (!map || iter < 0) - return -EINVAL; + if (!map || iter < 0) + return -EINVAL; - if (iter == map->end_iterator) - return 1; - else - return 0; + if (iter == map->end_iterator) + return 1; + else + return 0; } /* @@ -298,37 +308,40 @@ hashmap_is_end(hashmap_t map, hashmap_iter iter) * an "end-iterator" if the key wasn't found */ hashmap_iter -hashmap_find(hashmap_t map, const char *key) +hashmap_find (hashmap_t map, const char *key) { - unsigned int i; - hashmap_iter iter = 0; - struct hashentry_s *ptr; - - assert(map != NULL); - assert(key != NULL); - - if (!map || !key) - return -EINVAL; - - /* - * Loop through all the keys and look for the first occurrence - * of a particular key. - */ - for (i = 0; i != map->size; i++) { - ptr = map->buckets[i].head; - - while (ptr) { - if (strcasecmp(ptr->key, key) == 0) { - /* Found it, so return the current count */ - return iter; - } - - iter++; - ptr = ptr->next; - } - } - - return iter; + unsigned int i; + hashmap_iter iter = 0; + struct hashentry_s *ptr; + + assert (map != NULL); + assert (key != NULL); + + if (!map || !key) + return -EINVAL; + + /* + * Loop through all the keys and look for the first occurrence + * of a particular key. + */ + for (i = 0; i != map->size; i++) + { + ptr = map->buckets[i].head; + + while (ptr) + { + if (strcasecmp (ptr->key, key) == 0) + { + /* Found it, so return the current count */ + return iter; + } + + iter++; + ptr = ptr->next; + } + } + + return iter; } /* @@ -338,37 +351,41 @@ hashmap_find(hashmap_t map, const char *key) * negative upon error */ 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; - struct hashentry_s *ptr; - hashmap_iter count = 0; - - assert(map != NULL); - assert(iter >= 0); - assert(iter != map->end_iterator); - assert(key != NULL); - assert(data != NULL); - - if (!map || iter < 0 || !key || !data) - return -EINVAL; - - for (i = 0; i != map->size; i++) { - ptr = map->buckets[i].head; - while (ptr) { - if (count == iter) { - /* This is the data so return it */ - *key = ptr->key; - *data = ptr->data; - return ptr->len; - } - - ptr = ptr->next; - count++; - } - } - - return -EFAULT; + unsigned int i; + struct hashentry_s *ptr; + hashmap_iter count = 0; + + assert (map != NULL); + assert (iter >= 0); + assert (iter != map->end_iterator); + assert (key != NULL); + assert (data != NULL); + + if (!map || iter < 0 || !key || !data) + return -EINVAL; + + for (i = 0; i != map->size; i++) + { + ptr = map->buckets[i].head; + while (ptr) + { + if (count == iter) + { + /* This is the data so return it */ + *key = ptr->key; + *data = ptr->data; + return ptr->len; + } + + ptr = ptr->next; + count++; + } + } + + return -EFAULT; } /* @@ -379,31 +396,32 @@ hashmap_return_entry(hashmap_t map, hashmap_iter iter, char **key, void **data) * count found */ ssize_t -hashmap_search(hashmap_t map, const char *key) +hashmap_search (hashmap_t map, const char *key) { - int hash; - struct hashentry_s *ptr; - ssize_t count = 0; + int hash; + struct hashentry_s *ptr; + ssize_t count = 0; - if (map == NULL || key == NULL) - return -EINVAL; + if (map == NULL || key == NULL) + return -EINVAL; - hash = hashfunc(key, map->size); - if (hash < 0) - return hash; + hash = hashfunc (key, map->size); + if (hash < 0) + 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 */ - while (ptr) { - if (strcasecmp(ptr->key, key) == 0) - ++count; + /* All right, there is an entry here, now see if it's the one we want */ + while (ptr) + { + if (strcasecmp (ptr->key, key) == 0) + ++count; - /* This entry didn't contain the key; move to the next one */ - ptr = ptr->next; - } + /* This entry didn't contain the key; move to the next one */ + 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 */ 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; - struct hashentry_s *ptr; + int hash; + struct hashentry_s *ptr; - if (!map || !key || !data) - return -EINVAL; + if (!map || !key || !data) + return -EINVAL; - hash = hashfunc(key, map->size); - if (hash < 0) - return hash; + hash = hashfunc (key, map->size); + if (hash < 0) + return hash; - ptr = map->buckets[hash].head; + ptr = map->buckets[hash].head; - while (ptr) { - if (strcasecmp(ptr->key, key) == 0) { - *data = ptr->data; - return ptr->len; - } + while (ptr) + { + if (strcasecmp (ptr->key, key) == 0) + { + *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 */ ssize_t -hashmap_remove(hashmap_t map, const char *key) +hashmap_remove (hashmap_t map, const char *key) { - int hash; - struct hashentry_s *ptr, *next; - short int deleted = 0; - - if (map == NULL || key == NULL) - return -EINVAL; - - hash = hashfunc(key, map->size); - if (hash < 0) - return hash; - - ptr = map->buckets[hash].head; - while (ptr) { - if (strcasecmp(ptr->key, key) == 0) { - /* - * Found the data, now need to remove everything - * and update the hashmap. - */ - next = ptr->next; - - if (ptr->prev) - ptr->prev->next = ptr->next; - if (ptr->next) - ptr->next->prev = ptr->prev; - - if (map->buckets[hash].head == ptr) - map->buckets[hash].head = ptr->next; - if (map->buckets[hash].tail == ptr) - map->buckets[hash].tail = ptr->prev; - - safefree(ptr->key); - safefree(ptr->data); - safefree(ptr); - - ++deleted; - --map->end_iterator; - - ptr = next; - continue; - } - - /* This entry didn't contain the key; move to the next one */ - ptr = ptr->next; - } - - /* The key was not found, so return 0 */ - return deleted; + int hash; + struct hashentry_s *ptr, *next; + short int deleted = 0; + + if (map == NULL || key == NULL) + return -EINVAL; + + hash = hashfunc (key, map->size); + if (hash < 0) + return hash; + + ptr = map->buckets[hash].head; + while (ptr) + { + if (strcasecmp (ptr->key, key) == 0) + { + /* + * Found the data, now need to remove everything + * and update the hashmap. + */ + next = ptr->next; + + if (ptr->prev) + ptr->prev->next = ptr->next; + if (ptr->next) + ptr->next->prev = ptr->prev; + + if (map->buckets[hash].head == ptr) + map->buckets[hash].head = ptr->next; + if (map->buckets[hash].tail == ptr) + map->buckets[hash].tail = ptr->prev; + + safefree (ptr->key); + safefree (ptr->data); + safefree (ptr); + + ++deleted; + --map->end_iterator; + + ptr = next; + continue; + } + + /* This entry didn't contain the key; move to the next one */ + ptr = ptr->next; + } + + /* The key was not found, so return 0 */ + return deleted; } diff --git a/src/hashmap.h b/src/hashmap.h index 0bde82c..946b619 100644 --- a/src/hashmap.h +++ b/src/hashmap.h @@ -23,7 +23,8 @@ /* Allow the use in C++ code. */ #if defined(__cplusplus) -extern "C" { +extern "C" +{ #endif /* @@ -31,15 +32,15 @@ extern "C" { * 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. :) */ - typedef struct hashmap_s *hashmap_t; - typedef int hashmap_iter; + typedef struct hashmap_s *hashmap_t; + typedef int hashmap_iter; /* * hashmap_create() takes one argument, which is the number of buckets to * use internally. hashmap_delete() is self explanatory. */ - extern hashmap_t hashmap_create(unsigned int nbuckets); - extern int hashmap_delete(hashmap_t map); + extern hashmap_t hashmap_create (unsigned int nbuckets); + extern int hashmap_delete (hashmap_t map); /* * 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 * 0 upon successful insert */ - extern int hashmap_insert(hashmap_t map, const char *key, - const void *data, size_t len); + extern int hashmap_insert (hashmap_t map, const char *key, + const void *data, size_t len); /* * Get an iterator to the first entry. * * 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. @@ -66,7 +67,7 @@ extern "C" { * Returns: 1 if it is the end * 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 @@ -76,7 +77,7 @@ extern "C" { * an "iterator" pointing at the first key * 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. @@ -86,8 +87,8 @@ extern "C" { * Returns: the length of the data block upon success * negative upon error */ - extern ssize_t hashmap_return_entry(hashmap_t map, hashmap_iter iter, - char **key, void **data); + extern ssize_t hashmap_return_entry (hashmap_t map, hashmap_iter iter, + char **key, void **data); /* * 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 * length of data for the entry */ - extern ssize_t hashmap_entry_by_key(hashmap_t map, const char *key, - void **data); + extern ssize_t hashmap_entry_by_key (hashmap_t map, const char *key, + void **data); /* * Searches for _any_ occurrances of "key" within the hashmap and returns the @@ -108,7 +109,7 @@ extern "C" { * zero if no key is found * 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. @@ -118,9 +119,9 @@ extern "C" { * 0 if the key was not found * 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) } -#endif /* C++ */ -#endif /* _HASHMAP_H */ +#endif /* C++ */ +#endif /* _HASHMAP_H */ @@ -28,71 +28,72 @@ #include "text.h" void * -debugging_calloc(size_t nmemb, size_t size, const char *file, - unsigned long line) +debugging_calloc (size_t nmemb, size_t size, const char *file, + unsigned long line) { - void *ptr; + void *ptr; - assert(nmemb > 0); - assert(size > 0); + assert (nmemb > 0); + assert (size > 0); - ptr = calloc(nmemb, size); - fprintf(stderr, "{calloc: %p:%zu x %zu} %s:%lu\n", ptr, nmemb, size, file, - line); - return ptr; + ptr = calloc (nmemb, size); + fprintf (stderr, "{calloc: %p:%zu x %zu} %s:%lu\n", ptr, nmemb, size, file, + line); + return ptr; } 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); - fprintf(stderr, "{malloc: %p:%zu} %s:%lu\n", ptr, size, file, line); - return ptr; + ptr = malloc (size); + fprintf (stderr, "{malloc: %p:%zu} %s:%lu\n", ptr, size, file, line); + return ptr; } 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); - fprintf(stderr, "{realloc: %p -> %p:%zu} %s:%lu\n", ptr, newptr, size, - file, line); - return newptr; + newptr = realloc (ptr, size); + fprintf (stderr, "{realloc: %p -> %p:%zu} %s:%lu\n", ptr, newptr, size, + file, line); + return newptr; } 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) - free(ptr); - return; + if (ptr != NULL) + free (ptr); + return; } 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; - size_t len; + char *ptr; + size_t len; - assert(s != NULL); + assert (s != NULL); - len = strlen(s) + 1; - ptr = malloc(len); - if (!ptr) - return NULL; - memcpy(ptr, s, len); + len = strlen (s) + 1; + ptr = malloc (len); + if (!ptr) + return NULL; + memcpy (ptr, s, len); - fprintf(stderr, "{strdup: %p:%zu} %s:%lu\n", ptr, len, file, line); - return ptr; + fprintf (stderr, "{strdup: %p:%zu} %s:%lu\n", ptr, len, file, line); + return ptr; } /* @@ -104,32 +105,32 @@ debugging_strdup(const char *s, const char *file, unsigned long line) * solution. */ void * -malloc_shared_memory(size_t size) +malloc_shared_memory (size_t size) { - int fd; - void *ptr; - char buffer[32]; + int fd; + void *ptr; + 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 - * of glibc so that mkstemp() doesn't make us vulnerable. - */ - umask(0177); + /* Only allow u+rw bits. This may be required for some versions + * of glibc so that mkstemp() doesn't make us vulnerable. + */ + umask (0177); - if ((fd = mkstemp(buffer)) == -1) - return MAP_FAILED; - unlink(buffer); + if ((fd = mkstemp (buffer)) == -1) + return MAP_FAILED; + unlink (buffer); - if (ftruncate(fd, size) == -1) - return MAP_FAILED; - ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ftruncate (fd, size) == -1) + return MAP_FAILED; + 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. */ void * -calloc_shared_memory(size_t nmemb, size_t size) +calloc_shared_memory (size_t nmemb, size_t size) { - void *ptr; - long length; + void *ptr; + long length; - assert(nmemb > 0); - assert(size > 0); + assert (nmemb > 0); + assert (size > 0); - length = nmemb * size; + length = nmemb * size; - ptr = malloc_shared_memory(length); - if (ptr == MAP_FAILED) - return ptr; + ptr = malloc_shared_memory (length); + if (ptr == MAP_FAILED) + return ptr; - memset(ptr, 0, length); + memset (ptr, 0, length); - return ptr; + return ptr; } @@ -26,15 +26,15 @@ */ #ifndef NDEBUG -extern void *debugging_calloc(size_t nmemb, size_t size, const char *file, - unsigned long line); -extern void *debugging_malloc(size_t size, 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, - unsigned long line); -extern char *debugging_strdup(const char *s, const char *file, - unsigned long line); +extern void *debugging_calloc (size_t nmemb, size_t size, const char *file, + unsigned long line); +extern void *debugging_malloc (size_t size, 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, + unsigned long line); +extern char *debugging_strdup (const char *s, const char *file, + unsigned long line); # define safecalloc(x, y) debugging_calloc(x, y, __FILE__, __LINE__) # define safemalloc(x) debugging_malloc(x, __FILE__, __LINE__) @@ -60,7 +60,7 @@ free(*__safefree_tmp); \ /* * Allocate memory from the "shared" region of memory. */ -extern void *malloc_shared_memory(size_t size); -extern void *calloc_shared_memory(size_t nmemb, size_t size); +extern void *malloc_shared_memory (size_t size); +extern void *calloc_shared_memory (size_t nmemb, size_t size); #endif diff --git a/src/html-error.c b/src/html-error.c index 1802cde..ac4531b 100644 --- a/src/html-error.c +++ b/src/html-error.c @@ -33,77 +33,77 @@ /* * 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 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); - if (!config.errorpages) - return (-1); + config.errorpages = hashmap_create (ERRPAGES_BUCKETCOUNT); + if (!config.errorpages) + return (-1); - snprintf(errornbuf, ERRORNUM_BUFSIZE, "%u", errornum); + snprintf (errornbuf, ERRORNUM_BUFSIZE, "%u", errornum); - if (hashmap_insert(config.errorpages, errornbuf, - filepath, strlen(filepath) + 1) < 0) - return (-1); + if (hashmap_insert (config.errorpages, errornbuf, + filepath, strlen (filepath) + 1) < 0) + return (-1); - return (0); + return (0); } /* * Get the file appropriate for a given error. */ static char * -get_html_file(unsigned int errornum) +get_html_file (unsigned int errornum) { - hashmap_iter result_iter; - char errornbuf[ERRORNUM_BUFSIZE]; - char *key; - static char *val; + hashmap_iter result_iter; + char errornbuf[ERRORNUM_BUFSIZE]; + char *key; + static char *val; - assert(errornum >= 100 && errornum < 1000); + assert (errornum >= 100 && errornum < 1000); - if (!config.errorpages) - return (config.errorpage_undef); + if (!config.errorpages) + 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)) - return (config.errorpage_undef); + if (hashmap_is_end (config.errorpages, result_iter)) + return (config.errorpage_undef); - if (hashmap_return_entry(config.errorpages, result_iter, - &key, (void **)&val) < 0) - return (config.errorpage_undef); + if (hashmap_return_entry (config.errorpages, result_iter, + &key, (void **) &val) < 0) + return (config.errorpage_undef); - return (val); + return (val); } /* * Look up the value for a variable. */ static char * -lookup_variable(struct conn_s *connptr, char *varname) +lookup_variable (struct conn_s *connptr, char *varname) { - hashmap_iter result_iter; - char *key; - static char *data; + hashmap_iter result_iter; + char *key; + 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)) - return (NULL); + if (hashmap_is_end (connptr->error_variables, result_iter)) + return (NULL); - if (hashmap_return_entry(connptr->error_variables, result_iter, - &key, (void **)&data) < 0) - return (NULL); + if (hashmap_return_entry (connptr->error_variables, result_iter, + &key, (void **) &data) < 0) + return (NULL); - return (data); + return (data); } #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. */ 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 *varval; - int in_variable = 0, writeret; - - while (fgets(inbuf, HTML_BUFSIZE, infile) != NULL) { - for (p = inbuf; *p; p++) { - switch (*p) { - case '}': - if (in_variable) { - *p = '\0'; - if (! - (varval = - lookup_variable(connptr, - varstart))) - varval = "(unknown)"; - writeret = - write_message(connptr->client_fd, - "%s", varval); - if (writeret) - return (writeret); - in_variable = 0; - } else { - writeret = - write_message(connptr->client_fd, - "%c", *p); - if (writeret) - return (writeret); - } - break; - case '{': - /* a {{ will print a single {. If we are NOT - * already in a { variable, then proceed with - * setup. If we ARE already in a { variable, - * this code will fallthrough to the code that - * just dumps a character to the client fd. - */ - if (!in_variable) { - varstart = p + 1; - in_variable++; - } else - in_variable = 0; - default: - if (!in_variable) { - writeret = - write_message(connptr->client_fd, - "%c", *p); - if (writeret) - return (writeret); - } - - } - } - in_variable = 0; - } - return (0); + char inbuf[HTML_BUFSIZE], *varstart = NULL, *p; + char *varval; + int in_variable = 0, writeret; + + while (fgets (inbuf, HTML_BUFSIZE, infile) != NULL) + { + for (p = inbuf; *p; p++) + { + switch (*p) + { + case '}': + if (in_variable) + { + *p = '\0'; + if (!(varval = lookup_variable (connptr, varstart))) + varval = "(unknown)"; + writeret = write_message (connptr->client_fd, "%s", varval); + if (writeret) + return (writeret); + in_variable = 0; + } + else + { + writeret = write_message (connptr->client_fd, "%c", *p); + if (writeret) + return (writeret); + } + break; + case '{': + /* a {{ will print a single {. If we are NOT + * already in a { variable, then proceed with + * setup. If we ARE already in a { variable, + * this code will fallthrough to the code that + * just dumps a character to the client fd. + */ + if (!in_variable) + { + varstart = p + 1; + in_variable++; + } + else + in_variable = 0; + default: + if (!in_variable) + { + writeret = write_message (connptr->client_fd, "%c", *p); + if (writeret) + return (writeret); + } + + } + } + in_variable = 0; + } + return (0); } 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 = - "HTTP/1.0 %d %s\r\n" - "Server: %s/%s\r\n" - "Content-Type: text/html\r\n" "Connection: close\r\n" "\r\n"; + char *headers = + "HTTP/1.0 %d %s\r\n" + "Server: %s/%s\r\n" + "Content-Type: text/html\r\n" "Connection: close\r\n" "\r\n"; - return (write_message(connptr->client_fd, headers, - code, message, PACKAGE, VERSION)); + return (write_message (connptr->client_fd, headers, + code, message, PACKAGE, VERSION)); } /* * Display an error to the client. */ int -send_http_error_message(struct conn_s *connptr) +send_http_error_message (struct conn_s *connptr) { - char *error_file; - FILE *infile; - int ret; - char *fallback_error = - "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" - "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n" - "<html>\n" - "<head><title>%d %s</title></head>\n" - "<body>\n" - "<h1>%s</h1>\n" - "<p>%s</p>\n" - "<hr />\n" - "<p><em>Generated by %s version %s.</em></p>\n" - "</body>\n" - "</html>\n"; - - send_http_headers(connptr, connptr->error_number, - connptr->error_string); - - error_file = get_html_file(connptr->error_number); - if (!(infile = fopen(error_file, "r"))) { - char *detail = lookup_variable(connptr, "detail"); - return (write_message(connptr->client_fd, fallback_error, - connptr->error_number, - connptr->error_string, - connptr->error_string, - detail, - PACKAGE, VERSION)); - } - - ret = send_html_file(infile, connptr); - fclose(infile); - return (ret); + char *error_file; + FILE *infile; + int ret; + char *fallback_error = + "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n" + "<html>\n" + "<head><title>%d %s</title></head>\n" + "<body>\n" + "<h1>%s</h1>\n" + "<p>%s</p>\n" + "<hr />\n" + "<p><em>Generated by %s version %s.</em></p>\n" "</body>\n" "</html>\n"; + + send_http_headers (connptr, connptr->error_number, connptr->error_string); + + error_file = get_html_file (connptr->error_number); + if (!(infile = fopen (error_file, "r"))) + { + char *detail = lookup_variable (connptr, "detail"); + return (write_message (connptr->client_fd, fallback_error, + connptr->error_number, + connptr->error_string, + connptr->error_string, + detail, PACKAGE, VERSION)); + } + + ret = send_html_file (infile, connptr); + fclose (infile); + return (ret); } /* @@ -231,16 +228,14 @@ send_http_error_message(struct conn_s *connptr) #define ERRVAR_BUCKETCOUNT 16 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 = - hashmap_create(ERRVAR_BUCKETCOUNT))) - return (-1); - - return hashmap_insert(connptr->error_variables, key, val, - strlen(val) + 1); + if (!connptr->error_variables) + if (!(connptr->error_variables = hashmap_create (ERRVAR_BUCKETCOUNT))) + return (-1); + + return hashmap_insert (connptr->error_variables, key, val, + strlen (val) + 1); } #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 */ int -add_standard_vars(struct conn_s *connptr) +add_standard_vars (struct conn_s *connptr) { - char errnobuf[16]; - char timebuf[30]; - time_t global_time; + char errnobuf[16]; + char timebuf[30]; + time_t global_time; - snprintf(errnobuf, sizeof errnobuf, "%d", connptr->error_number); - ADD_VAR_RET("errno", errnobuf); + snprintf (errnobuf, sizeof errnobuf, "%d", connptr->error_number); + ADD_VAR_RET ("errno", errnobuf); - ADD_VAR_RET("cause", connptr->error_string); - ADD_VAR_RET("request", connptr->request_line); - ADD_VAR_RET("clientip", connptr->client_ip_addr); - ADD_VAR_RET("clienthost", connptr->client_string_addr); + ADD_VAR_RET ("cause", connptr->error_string); + ADD_VAR_RET ("request", connptr->request_line); + ADD_VAR_RET ("clientip", connptr->client_ip_addr); + ADD_VAR_RET ("clienthost", connptr->client_string_addr); - /* The following value parts are all non-NULL and will - * trigger warnings in ADD_VAR_RET(), so we use - * add_error_variable() directly. - */ + /* The following value parts are all non-NULL and will + * trigger warnings in ADD_VAR_RET(), so we use + * add_error_variable() directly. + */ - global_time = time(NULL); - strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", - gmtime(&global_time)); - add_error_variable(connptr, "date", timebuf); + global_time = time (NULL); + strftime (timebuf, sizeof (timebuf), "%a, %d %b %Y %H:%M:%S GMT", + gmtime (&global_time)); + add_error_variable (connptr, "date", timebuf); - add_error_variable(connptr, "website", "http://tinyproxy.banu.com/"); - add_error_variable(connptr, "version", VERSION); - add_error_variable(connptr, "package", PACKAGE); + add_error_variable (connptr, "website", "http://tinyproxy.banu.com/"); + add_error_variable (connptr, "version", VERSION); + add_error_variable (connptr, "package", PACKAGE); - return (0); + return (0); } /* * Add the error information to the conn structure. */ 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; - char *key, *val; + va_list ap; + char *key, *val; - va_start(ap, message); + va_start (ap, message); - while ((key = va_arg(ap, char *))) { - val = va_arg(ap, char *); + while ((key = va_arg (ap, char *))) + { + val = va_arg (ap, char *); - if (add_error_variable(connptr, key, val) == -1) { - va_end(ap); - return (-1); - } - } + if (add_error_variable (connptr, key, val) == -1) + { + va_end (ap); + return (-1); + } + } - connptr->error_number = number; - connptr->error_string = safestrdup(message); + connptr->error_number = number; + connptr->error_string = safestrdup (message); - va_end(ap); + va_end (ap); - return (add_standard_vars(connptr)); + return (add_standard_vars (connptr)); } diff --git a/src/html-error.h b/src/html-error.h index 2e35b5b..280101c 100644 --- a/src/html-error.h +++ b/src/html-error.h @@ -24,13 +24,14 @@ /* Forward declaration */ struct conn_s; -extern int add_new_errorpage(char *filepath, unsigned int errornum); -extern int send_http_error_message(struct conn_s *connptr); -extern int indicate_http_error(struct conn_s *connptr, int number, - char *message, ...); -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_http_headers(struct conn_s *connptr, int code, char *message); -extern int add_standard_vars(struct conn_s *connptr); +extern int add_new_errorpage (char *filepath, unsigned int errornum); +extern int send_http_error_message (struct conn_s *connptr); +extern int indicate_http_error (struct conn_s *connptr, int number, + char *message, ...); +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_http_headers (struct conn_s *connptr, int code, + char *message); +extern int add_standard_vars (struct conn_s *connptr); -#endif /* !TINYPROXY_HTML_ERROR_H */ +#endif /* !TINYPROXY_HTML_ERROR_H */ diff --git a/src/http-message.c b/src/http-message.c index eadf37f..2cd5a4d 100644 --- a/src/http-message.c +++ b/src/http-message.c @@ -30,29 +30,33 @@ * Also, the caller MUST NOT free the memory while the structure is * still in use---bad things would happen. */ -struct http_message_s { - /* Response string and code supplied on the HTTP status line */ - struct { - const char *string; - int code; - } response; - - /* - * A group of headers to be sent with this message. Right now - * the strings are referenced through pointers in an array. - * I might change this to a vector in the future. - */ - struct { - char **strings; - unsigned int total; - unsigned int used; - } headers; - - /* Body of the message (most likely an HTML message) */ - struct { - const char *text; - size_t length; - } body; +struct http_message_s +{ + /* Response string and code supplied on the HTTP status line */ + struct + { + const char *string; + int code; + } response; + + /* + * A group of headers to be sent with this message. Right now + * the strings are referenced through pointers in an array. + * I might change this to a vector in the future. + */ + struct + { + char **strings; + unsigned int total; + unsigned int used; + } headers; + + /* Body of the message (most likely an HTML message) */ + struct + { + const char *text; + size_t length; + } body; }; /* @@ -61,18 +65,18 @@ struct http_message_s { * number is returned. Useful for if() tests and assert() tests. */ static int -is_http_message_valid(http_message_t msg) +is_http_message_valid (http_message_t msg) { - if (msg == NULL) - return 0; - if (msg->headers.strings == NULL) - return 0; - if (msg->response.string == NULL) - return 0; - if (msg->response.code < 1 || msg->response.code > 999) - return 0; - - return 1; + if (msg == NULL) + return 0; + if (msg->headers.strings == NULL) + return 0; + if (msg->response.string == NULL) + return 0; + if (msg->response.code < 1 || msg->response.code > 999) + return 0; + + return 1; } /* 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. */ 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; - int ret; - - msg = safecalloc(1, sizeof(struct http_message_s)); - if (msg == NULL) - return NULL; - - msg->headers.strings = safecalloc(NUMBER_OF_HEADERS, sizeof(char *)); - if (msg->headers.strings == NULL) { - safefree(msg); - return NULL; - } - - msg->headers.total = NUMBER_OF_HEADERS; - - /* Store the HTTP response information in the structure */ - ret = http_message_set_response(msg, response_code, response_string); - if (IS_HTTP_MSG_ERROR(ret)) { - safefree(msg->headers.strings); - safefree(msg); - return NULL; - } - - return msg; + http_message_t msg; + int ret; + + msg = safecalloc (1, sizeof (struct http_message_s)); + if (msg == NULL) + return NULL; + + msg->headers.strings = safecalloc (NUMBER_OF_HEADERS, sizeof (char *)); + if (msg->headers.strings == NULL) + { + safefree (msg); + return NULL; + } + + msg->headers.total = NUMBER_OF_HEADERS; + + /* Store the HTTP response information in the structure */ + ret = http_message_set_response (msg, response_code, response_string); + if (IS_HTTP_MSG_ERROR (ret)) + { + safefree (msg->headers.strings); + safefree (msg); + return NULL; + } + + return msg; } /* @@ -117,19 +123,19 @@ http_message_create(int response_code, const char *response_string) * is the responsibility of the caller. */ int -http_message_destroy(http_message_t msg) +http_message_destroy (http_message_t msg) { - assert(msg != NULL); - assert(msg->headers.strings != NULL); + assert (msg != NULL); + assert (msg->headers.strings != NULL); - /* Check for valid arguments */ - if (msg == NULL) - return -EFAULT; + /* Check for valid arguments */ + if (msg == NULL) + return -EFAULT; - if (msg->headers.strings != NULL) - safefree(msg->headers.strings); - safefree(msg); - return 0; + if (msg->headers.strings != NULL) + safefree (msg->headers.strings); + safefree (msg); + return 0; } /* @@ -137,135 +143,135 @@ http_message_destroy(http_message_t msg) * must be a NUL ('\0') terminated C string. */ int -http_message_set_response(http_message_t msg, - int response_code, const char *response_string) +http_message_set_response (http_message_t msg, + int response_code, const char *response_string) { - /* Check for valid arguments */ - if (msg == NULL) - return -EFAULT; - if (response_code < 1 || response_code > 999) - return -EINVAL; - if (response_string == NULL) - return -EINVAL; - if (strlen(response_string) == 0) - return -EINVAL; - - msg->response.code = response_code; - msg->response.string = response_string; - - return 0; + /* Check for valid arguments */ + if (msg == NULL) + return -EFAULT; + if (response_code < 1 || response_code > 999) + return -EINVAL; + if (response_string == NULL) + return -EINVAL; + if (strlen (response_string) == 0) + return -EINVAL; + + msg->response.code = response_code; + msg->response.string = response_string; + + return 0; } /* * Set the HTTP message body. */ 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 */ - if (msg == NULL) - return -EFAULT; - if (body == NULL) - return -EINVAL; - if (len == 0) - return -EINVAL; - - msg->body.text = body; - msg->body.length = len; - - return 0; + /* Check for valid arguments */ + if (msg == NULL) + return -EFAULT; + if (body == NULL) + return -EINVAL; + if (len == 0) + return -EINVAL; + + msg->body.text = body; + msg->body.length = len; + + return 0; } /* * Add headers to the structure. */ 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; - int i; - - /* Check for valid arguments */ - if (msg == NULL) - return -EFAULT; - if (headers == NULL) - return -EINVAL; - if (num_headers < 1) - return -EINVAL; - - /* - * If the number of headers to add is greater than the space - * available, reallocate the memory. - */ - if (msg->headers.used + num_headers > msg->headers.total) { - new_headers = safecalloc(msg->headers.total * 2, - sizeof(char *)); - if (new_headers == NULL) - return -ENOMEM; - - /* Copy the array */ - for (i = 0; i != msg->headers.used; ++i) - new_headers[i] = msg->headers.strings[i]; - - /* Remove the old array and replace it with the new array */ - safefree(msg->headers.strings); - msg->headers.strings = new_headers; - msg->headers.total *= 2; - } - - /* - * Add the new headers to the structure - */ - for (i = 0; i != num_headers; ++i) - msg->headers.strings[i + msg->headers.used] = headers[i]; - msg->headers.used += num_headers; - - return 0; + char **new_headers; + int i; + + /* Check for valid arguments */ + if (msg == NULL) + return -EFAULT; + if (headers == NULL) + return -EINVAL; + if (num_headers < 1) + return -EINVAL; + + /* + * If the number of headers to add is greater than the space + * available, reallocate the memory. + */ + if (msg->headers.used + num_headers > msg->headers.total) + { + new_headers = safecalloc (msg->headers.total * 2, sizeof (char *)); + if (new_headers == NULL) + return -ENOMEM; + + /* Copy the array */ + for (i = 0; i != msg->headers.used; ++i) + new_headers[i] = msg->headers.strings[i]; + + /* Remove the old array and replace it with the new array */ + safefree (msg->headers.strings); + msg->headers.strings = new_headers; + msg->headers.total *= 2; + } + + /* + * Add the new headers to the structure + */ + for (i = 0; i != num_headers; ++i) + msg->headers.strings[i + msg->headers.used] = headers[i]; + msg->headers.used += num_headers; + + return 0; } /* * Send the completed HTTP message via the supplied file descriptor. */ int -http_message_send(http_message_t msg, int fd) +http_message_send (http_message_t msg, int fd) { - char timebuf[30]; - time_t global_time; - unsigned int i; + char timebuf[30]; + time_t global_time; + unsigned int i; - assert(is_http_message_valid(msg)); + assert (is_http_message_valid (msg)); - /* Check for valid arguments */ - if (msg == NULL) - return -EFAULT; - if (fd < 1) - return -EBADF; - if (!is_http_message_valid(msg)) - return -EINVAL; + /* Check for valid arguments */ + if (msg == NULL) + return -EFAULT; + if (fd < 1) + return -EBADF; + if (!is_http_message_valid (msg)) + return -EINVAL; - /* Write the response line */ - write_message(fd, "HTTP/1.0 %d %s\r\n", - msg->response.code, msg->response.string); + /* Write the response line */ + write_message (fd, "HTTP/1.0 %d %s\r\n", + msg->response.code, msg->response.string); - /* Go through all the headers */ - for (i = 0; i != msg->headers.used; ++i) - write_message(fd, "%s\r\n", msg->headers.strings[i]); + /* Go through all the headers */ + for (i = 0; i != msg->headers.used; ++i) + write_message (fd, "%s\r\n", msg->headers.strings[i]); - /* Output the date */ - global_time = time(NULL); - strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", - gmtime(&global_time)); - write_message(fd, "Date: %s\r\n", timebuf); + /* Output the date */ + global_time = time (NULL); + strftime (timebuf, sizeof (timebuf), "%a, %d %b %Y %H:%M:%S GMT", + gmtime (&global_time)); + write_message (fd, "Date: %s\r\n", timebuf); - /* Output the content-length */ - write_message(fd, "Content-length: %u\r\n", msg->body.length); + /* Output the content-length */ + write_message (fd, "Content-length: %u\r\n", msg->body.length); - /* Write the separator between the headers and body */ - safe_write(fd, "\r\n", 2); + /* Write the separator between the headers and body */ + safe_write (fd, "\r\n", 2); - /* If there's a body, send it! */ - if (msg->body.length > 0) - safe_write(fd, msg->body.text, msg->body.length); + /* If there's a body, send it! */ + if (msg->body.length > 0) + safe_write (fd, msg->body.text, msg->body.length); - return 0; + return 0; } diff --git a/src/http-message.h b/src/http-message.h index 36c5cc3..b83df11 100644 --- a/src/http-message.h +++ b/src/http-message.h @@ -58,28 +58,28 @@ typedef struct http_message_s *http_message_t; #define IS_HTTP_MSG_ERROR(x) (x < 0) /* Initialize the internal structure of the HTTP message */ -extern http_message_t http_message_create(int response_code, - const char *response_string); +extern http_message_t http_message_create (int response_code, + const char *response_string); /* 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 * 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 * body of the message, update the response information, or * add a new set of headers. */ -extern int http_message_set_body(http_message_t msg, - const char *body, size_t len); -extern int http_message_set_response(http_message_t msg, - int response_code, - const char *response_string); +extern int http_message_set_body (http_message_t msg, + const char *body, size_t len); +extern int http_message_set_response (http_message_t msg, + int response_code, + const char *response_string); /* * 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 * sent. */ -extern int http_message_add_headers(http_message_t msg, - char **headers, int num_headers); +extern int http_message_add_headers (http_message_t msg, + char **headers, int num_headers); -#endif /* _TINYPROXY_HTTP_MESSAGE_H_ */ +#endif /* _TINYPROXY_HTTP_MESSAGE_H_ */ @@ -29,15 +29,15 @@ #include "vector.h" static char *syslog_level[] = { - NULL, - NULL, - "CRITICAL", - "ERROR", - "WARNING", - "NOTICE", - "INFO", - "DEBUG", - "CONNECT" + NULL, + NULL, + "CRITICAL", + "ERROR", + "WARNING", + "NOTICE", + "INFO", + "DEBUG", + "CONNECT" }; #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. */ 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); - return log_file_fd; + log_file_fd = create_file_safely (log_file_name, FALSE); + return log_file_fd; } /* * Close the log file */ void -close_log_file(void) +close_log_file (void) { - close(log_file_fd); + close (log_file_fd); } /* * Truncate log file to a zero length. */ void -truncate_log_file(void) +truncate_log_file (void) { - lseek(log_file_fd, 0, SEEK_SET); - ftruncate(log_file_fd, 0); + lseek (log_file_fd, 0, SEEK_SET); + ftruncate (log_file_fd, 0); } /* * Set the log level for writing to the log file. */ 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. */ void -log_message(int level, char *fmt, ...) +log_message (int level, char *fmt, ...) { - va_list args; - time_t nowtime; + va_list args; + time_t nowtime; - char time_string[TIME_LENGTH]; - char str[STRING_LENGTH]; + char time_string[TIME_LENGTH]; + char str[STRING_LENGTH]; #ifdef NDEBUG - /* - * Figure out if we should write the message or not. - */ - if (log_level == LOG_CONN) { - if (level == LOG_INFO) - return; - } else if (log_level == LOG_INFO) { - if (level > LOG_INFO && level != LOG_CONN) - return; - } else if (level > log_level) - return; + /* + * Figure out if we should write the message or not. + */ + if (log_level == LOG_CONN) + { + if (level == LOG_INFO) + return; + } + else if (log_level == LOG_INFO) + { + if (level > LOG_INFO && level != LOG_CONN) + return; + } + else if (level > log_level) + return; #endif #ifdef HAVE_SYSLOG_H - if (config.syslog && level == LOG_CONN) - level = LOG_INFO; + if (config.syslog && level == LOG_CONN) + level = LOG_INFO; #endif - va_start(args, fmt); + va_start (args, fmt); - /* - * If the config file hasn't been processed, then we need to store - * the messages for later processing. - */ - if (!processed_config_file) { - char *entry_buffer; + /* + * If the config file hasn't been processed, then we need to store + * the messages for later processing. + */ + if (!processed_config_file) + { + char *entry_buffer; - if (!log_message_storage) { - log_message_storage = vector_create(); - if (!log_message_storage) - goto out; - } + if (!log_message_storage) + { + log_message_storage = vector_create (); + if (!log_message_storage) + goto out; + } - vsnprintf(str, STRING_LENGTH, fmt, args); + vsnprintf (str, STRING_LENGTH, fmt, args); - entry_buffer = safemalloc(strlen(str) + 6); - if (!entry_buffer) - goto out; + entry_buffer = safemalloc (strlen (str) + 6); + if (!entry_buffer) + goto out; - sprintf(entry_buffer, "%d %s", level, str); - vector_append(log_message_storage, entry_buffer, - strlen(entry_buffer) + 1); + sprintf (entry_buffer, "%d %s", level, str); + vector_append (log_message_storage, entry_buffer, + strlen (entry_buffer) + 1); - safefree(entry_buffer); - goto out; - } + safefree (entry_buffer); + goto out; + } #ifdef HAVE_SYSLOG_H - if (config.syslog) { + if (config.syslog) + { # ifdef HAVE_VSYSLOG_H - vsyslog(level, fmt, args); + vsyslog (level, fmt, args); # else - vsnprintf(str, STRING_LENGTH, fmt, args); - syslog(level, "%s", str); + vsnprintf (str, STRING_LENGTH, fmt, args); + syslog (level, "%s", str); # endif - } else { + } + else + { #endif - nowtime = time(NULL); - /* Format is month day hour:minute:second (24 time) */ - strftime(time_string, TIME_LENGTH, "%b %d %H:%M:%S", - localtime(&nowtime)); + nowtime = time (NULL); + /* Format is month day hour:minute:second (24 time) */ + strftime (time_string, TIME_LENGTH, "%b %d %H:%M:%S", + localtime (&nowtime)); - snprintf(str, STRING_LENGTH, "%-9s %s [%ld]: ", - syslog_level[level], time_string, (long int)getpid()); + snprintf (str, STRING_LENGTH, "%-9s %s [%ld]: ", + 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)); - vsnprintf(str, STRING_LENGTH, fmt, args); - write(log_file_fd, str, strlen(str)); - write(log_file_fd, "\n", 1); - fsync(log_file_fd); + write (log_file_fd, str, strlen (str)); + vsnprintf (str, STRING_LENGTH, fmt, args); + write (log_file_fd, str, strlen (str)); + write (log_file_fd, "\n", 1); + fsync (log_file_fd); #ifdef HAVE_SYSLOG_H - } + } #endif - out: - va_end(args); +out: + va_end (args); } /* * This needs to send any stored log messages. */ void -send_stored_logs(void) +send_stored_logs (void) { - char *string; - char *ptr; + char *string; + char *ptr; - int level; + int level; - size_t i; + size_t i; - for (i = 0; i != vector_length(log_message_storage); ++i) { - string = vector_getentry(log_message_storage, i, NULL); + for (i = 0; i != vector_length (log_message_storage); ++i) + { + string = vector_getentry (log_message_storage, i, NULL); - ptr = strchr(string, ' ') + 1; - level = atoi(string); + ptr = strchr (string, ' ') + 1; + level = atoi (string); #ifdef NDEBUG - if (log_level == LOG_CONN && level == LOG_INFO) - continue; - else if (log_level == LOG_INFO) { - if (level > LOG_INFO && level != LOG_CONN) - continue; - } else if (level > log_level) - continue; + if (log_level == LOG_CONN && level == LOG_INFO) + continue; + else if (log_level == LOG_INFO) + { + if (level > LOG_INFO && level != LOG_CONN) + continue; + } + else if (level > log_level) + continue; #endif - log_message(level, ptr); - } + log_message (level, ptr); + } - vector_delete(log_message_storage); - log_message_storage = NULL; + vector_delete (log_message_storage); + log_message_storage = NULL; } @@ -87,7 +87,7 @@ # define LOG_DEBUG 7 #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: @@ -102,12 +102,12 @@ # define DEBUG2(x, y...) do { } while(0) #endif -extern int open_log_file(const char *file); -extern void close_log_file(void); -extern void truncate_log_file(void); +extern int open_log_file (const char *file); +extern void close_log_file (void); +extern void truncate_log_file (void); -extern void log_message(int level, char *fmt, ...); -extern void set_log_level(int level); -extern void send_stored_logs(void); +extern void log_message (int level, char *fmt, ...); +extern void set_log_level (int level); +extern void send_stored_logs (void); #endif diff --git a/src/network.c b/src/network.c index 42feac3..7b4bb52 100644 --- a/src/network.c +++ b/src/network.c @@ -33,35 +33,37 @@ * again. Keep sending until the buffer has been sent. */ 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; - size_t bytestosend; + ssize_t len; + size_t bytestosend; - assert(fd >= 0); - assert(buffer != NULL); - assert(count > 0); + assert (fd >= 0); + assert (buffer != NULL); + assert (count > 0); - bytestosend = count; + bytestosend = count; - while (1) { - len = send(fd, buffer, bytestosend, MSG_NOSIGNAL); + while (1) + { + len = send (fd, buffer, bytestosend, MSG_NOSIGNAL); - if (len < 0) { - if (errno == EINTR) - continue; - else - return -errno; - } + if (len < 0) + { + if (errno == EINTR) + continue; + else + return -errno; + } - if (len == bytestosend) - break; + if (len == bytestosend) + break; - buffer += len; - bytestosend -= len; - } + buffer += len; + bytestosend -= len; + } - return count; + return count; } /* @@ -69,15 +71,17 @@ safe_write(int fd, const char *buffer, size_t count) * again. */ 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 { - len = read(fd, buffer, count); - } while (len < 0 && errno == EINTR); + do + { + 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. :) */ int -write_message(int fd, const char *fmt, ...) +write_message (int fd, const char *fmt, ...) { - ssize_t n; - size_t size = (1024 * 8); /* start with 8 KB and go from there */ - char *buf, *tmpbuf; - va_list ap; - - if ((buf = safemalloc(size)) == NULL) - return -1; - - while (1) { - va_start(ap, fmt); - n = vsnprintf(buf, size, fmt, ap); - va_end(ap); - - /* If that worked, break out so we can send the buffer */ - if (n > -1 && n < size) - break; - - /* Else, try again with more space */ - if (n > -1) - /* precisely what is needed (glibc2.1) */ - size = n + 1; - else - /* twice the old size (glibc2.0) */ - size *= 2; - - if ((tmpbuf = saferealloc(buf, size)) == NULL) { - safefree(buf); - return -1; - } else - buf = tmpbuf; - } - - if (safe_write(fd, buf, n) < 0) { - safefree(buf); - return -1; - } - - safefree(buf); - return 0; + ssize_t n; + size_t size = (1024 * 8); /* start with 8 KB and go from there */ + char *buf, *tmpbuf; + va_list ap; + + if ((buf = safemalloc (size)) == NULL) + return -1; + + while (1) + { + va_start (ap, fmt); + n = vsnprintf (buf, size, fmt, ap); + va_end (ap); + + /* If that worked, break out so we can send the buffer */ + if (n > -1 && n < size) + break; + + /* Else, try again with more space */ + if (n > -1) + /* precisely what is needed (glibc2.1) */ + size = n + 1; + else + /* twice the old size (glibc2.0) */ + size *= 2; + + if ((tmpbuf = saferealloc (buf, size)) == NULL) + { + safefree (buf); + return -1; + } + else + buf = tmpbuf; + } + + if (safe_write (fd, buf, n) < 0) + { + safefree (buf); + return -1; + } + + safefree (buf); + return 0; } /* @@ -142,103 +150,113 @@ write_message(int fd, const char *fmt, ...) #define SEGMENT_LEN (512) #define MAXIMUM_BUFFER_LENGTH (128 * 1024) ssize_t -readline(int fd, char **whole_buffer) +readline (int fd, char **whole_buffer) { - ssize_t whole_buffer_len; - char buffer[SEGMENT_LEN]; - char *ptr; - - ssize_t ret; - ssize_t diff; - - struct read_lines_s { - char *data; - size_t len; - struct read_lines_s *next; - }; - struct read_lines_s *first_line, *line_ptr; - - first_line = safecalloc(sizeof(struct read_lines_s), 1); - if (!first_line) - return -ENOMEM; - - line_ptr = first_line; - - whole_buffer_len = 0; - for (;;) { - ret = recv(fd, buffer, SEGMENT_LEN, MSG_PEEK); - if (ret <= 0) - goto CLEANUP; - - ptr = memchr(buffer, '\n', ret); - if (ptr) - diff = ptr - buffer + 1; - else - diff = ret; - - whole_buffer_len += diff; - - /* - * Don't allow the buffer to grow without bound. If we - * get to more than MAXIMUM_BUFFER_LENGTH close. - */ - if (whole_buffer_len > MAXIMUM_BUFFER_LENGTH) { - ret = -ERANGE; - goto CLEANUP; - } - - line_ptr->data = safemalloc(diff); - if (!line_ptr->data) { - ret = -ENOMEM; - goto CLEANUP; - } - - recv(fd, line_ptr->data, diff, 0); - line_ptr->len = diff; - - if (ptr) { - line_ptr->next = NULL; - break; - } - - line_ptr->next = safecalloc(sizeof(struct read_lines_s), 1); - if (!line_ptr->next) { - ret = -ENOMEM; - goto CLEANUP; - } - line_ptr = line_ptr->next; - } - - *whole_buffer = safemalloc(whole_buffer_len + 1); - if (!*whole_buffer) { - ret = -ENOMEM; - goto CLEANUP; - } - - *(*whole_buffer + whole_buffer_len) = '\0'; - - whole_buffer_len = 0; - line_ptr = first_line; - while (line_ptr) { - memcpy(*whole_buffer + whole_buffer_len, line_ptr->data, - line_ptr->len); - whole_buffer_len += line_ptr->len; - - line_ptr = line_ptr->next; - } - - ret = whole_buffer_len; - - CLEANUP: - do { - line_ptr = first_line->next; - if (first_line->data) - safefree(first_line->data); - safefree(first_line); - first_line = line_ptr; - } while (first_line); - - return ret; + ssize_t whole_buffer_len; + char buffer[SEGMENT_LEN]; + char *ptr; + + ssize_t ret; + ssize_t diff; + + struct read_lines_s + { + char *data; + size_t len; + struct read_lines_s *next; + }; + struct read_lines_s *first_line, *line_ptr; + + first_line = safecalloc (sizeof (struct read_lines_s), 1); + if (!first_line) + return -ENOMEM; + + line_ptr = first_line; + + whole_buffer_len = 0; + for (;;) + { + ret = recv (fd, buffer, SEGMENT_LEN, MSG_PEEK); + if (ret <= 0) + goto CLEANUP; + + ptr = memchr (buffer, '\n', ret); + if (ptr) + diff = ptr - buffer + 1; + else + diff = ret; + + whole_buffer_len += diff; + + /* + * Don't allow the buffer to grow without bound. If we + * get to more than MAXIMUM_BUFFER_LENGTH close. + */ + if (whole_buffer_len > MAXIMUM_BUFFER_LENGTH) + { + ret = -ERANGE; + goto CLEANUP; + } + + line_ptr->data = safemalloc (diff); + if (!line_ptr->data) + { + ret = -ENOMEM; + goto CLEANUP; + } + + recv (fd, line_ptr->data, diff, 0); + line_ptr->len = diff; + + if (ptr) + { + line_ptr->next = NULL; + break; + } + + line_ptr->next = safecalloc (sizeof (struct read_lines_s), 1); + if (!line_ptr->next) + { + ret = -ENOMEM; + goto CLEANUP; + } + line_ptr = line_ptr->next; + } + + *whole_buffer = safemalloc (whole_buffer_len + 1); + if (!*whole_buffer) + { + ret = -ENOMEM; + goto CLEANUP; + } + + *(*whole_buffer + whole_buffer_len) = '\0'; + + whole_buffer_len = 0; + line_ptr = first_line; + while (line_ptr) + { + memcpy (*whole_buffer + whole_buffer_len, line_ptr->data, + line_ptr->len); + whole_buffer_len += line_ptr->len; + + line_ptr = line_ptr->next; + } + + ret = whole_buffer_len; + +CLEANUP: + do + { + line_ptr = first_line->next; + if (first_line->data) + safefree (first_line->data); + safefree (first_line); + first_line = line_ptr; + } + while (first_line); + + return ret; } /* @@ -246,32 +264,35 @@ readline(int fd, char **whole_buffer) * hex string. */ 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(buf != NULL); - assert(buflen != 0); - buf[0] = '\0'; /* start with an empty string */ - - switch (sa->sa_family) { - case AF_INET:{ - struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; - - inet_ntop(AF_INET, &sa_in->sin_addr, buf, buflen); - break; - } - case AF_INET6:{ - struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; - - inet_ntop(AF_INET6, &sa_in6->sin6_addr, buf, buflen); - break; - } - default: - /* no valid family */ - return NULL; - } - - return buf; + assert (sa != NULL); + assert (buf != NULL); + assert (buflen != 0); + buf[0] = '\0'; /* start with an empty string */ + + switch (sa->sa_family) + { + case AF_INET: + { + struct sockaddr_in *sa_in = (struct sockaddr_in *) sa; + + inet_ntop (AF_INET, &sa_in->sin_addr, buf, buflen); + break; + } + case AF_INET6: + { + struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *) sa; + + inet_ntop (AF_INET6, &sa_in6->sin6_addr, buf, buflen); + break; + } + default: + /* no valid family */ + return NULL; + } + + return buf; } /* @@ -282,41 +303,42 @@ get_ip_string(struct sockaddr *sa, char *buf, size_t buflen) * Returns the same as inet_pton(). */ 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 */ - int n; - - assert(ip != NULL && strlen(ip) != 0); - assert(dst != NULL); - - /* - * Check if the string is an IPv4 numeric address. We use the - * older inet_aton() call since it handles more IPv4 numeric - * address formats. - */ - n = inet_aton(ip, (struct in_addr *)dst); - if (n == 0) { - /* - * Simple case: "ip" wasn't an IPv4 numeric address, so - * try doing the conversion as an IPv6 address. This - * will either succeed or fail, but we can't do any - * more processing anyway. - */ - return inet_pton(AF_INET6, ip, dst); - } - - /* - * "ip" was an IPv4 address, so we need to convert it to - * an IPv4-mapped IPv6 address and do the conversion - * again to get the IPv6 network structure. - * - * We convert the IPv4 binary address back into the - * standard dotted-decimal format using inet_ntop() - * so we can be sure that inet_pton will accept the - * full string. - */ - snprintf(buf, sizeof(buf), "::ffff:%s", - inet_ntop(AF_INET, dst, tmp, sizeof(tmp))); - return inet_pton(AF_INET6, buf, dst); + char buf[24], tmp[24]; /* IPv4->IPv6 = ::FFFF:xxx.xxx.xxx.xxx\0 */ + int n; + + assert (ip != NULL && strlen (ip) != 0); + assert (dst != NULL); + + /* + * Check if the string is an IPv4 numeric address. We use the + * older inet_aton() call since it handles more IPv4 numeric + * address formats. + */ + n = inet_aton (ip, (struct in_addr *) dst); + if (n == 0) + { + /* + * Simple case: "ip" wasn't an IPv4 numeric address, so + * try doing the conversion as an IPv6 address. This + * will either succeed or fail, but we can't do any + * more processing anyway. + */ + return inet_pton (AF_INET6, ip, dst); + } + + /* + * "ip" was an IPv4 address, so we need to convert it to + * an IPv4-mapped IPv6 address and do the conversion + * again to get the IPv6 network structure. + * + * We convert the IPv4 binary address back into the + * standard dotted-decimal format using inet_ntop() + * so we can be sure that inet_pton will accept the + * full string. + */ + snprintf (buf, sizeof (buf), "::ffff:%s", + inet_ntop (AF_INET, dst, tmp, sizeof (tmp))); + return inet_pton (AF_INET6, buf, dst); } diff --git a/src/network.h b/src/network.h index 3ba7d6a..b6ddaa6 100644 --- a/src/network.h +++ b/src/network.h @@ -21,13 +21,13 @@ #ifndef TINYPROXY_NETWORK_H #define TINYPROXY_NETWORK_H -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_write (int fd, const 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 ssize_t readline(int fd, char **whole_buffer); +extern int write_message (int fd, const char *fmt, ...); +extern ssize_t readline (int fd, char **whole_buffer); -extern char *get_ip_string(struct sockaddr *sa, char *buf, size_t len); -extern int full_inet_pton(const char *ip, void *dst); +extern char *get_ip_string (struct sockaddr *sa, char *buf, size_t len); +extern int full_inet_pton (const char *ip, void *dst); #endif @@ -81,20 +81,22 @@ static vector_t ports_allowed_by_connect = NULL; * it hasn't already by done. */ void -add_connect_port_allowed(int port) +add_connect_port_allowed (int port) { - if (!ports_allowed_by_connect) { - ports_allowed_by_connect = vector_create(); - if (!ports_allowed_by_connect) { - log_message(LOG_WARNING, - "Could not create a list of allowed CONNECT ports"); - return; - } - } - - log_message(LOG_INFO, "Adding Port [%d] to the list allowed by CONNECT", - port); - vector_append(ports_allowed_by_connect, (void **)&port, sizeof(port)); + if (!ports_allowed_by_connect) + { + ports_allowed_by_connect = vector_create (); + if (!ports_allowed_by_connect) + { + log_message (LOG_WARNING, + "Could not create a list of allowed CONNECT ports"); + return; + } + } + + log_message (LOG_INFO, "Adding Port [%d] to the list allowed by CONNECT", + port); + vector_append (ports_allowed_by_connect, (void **) &port, sizeof (port)); } /* @@ -104,25 +106,26 @@ add_connect_port_allowed(int port) * 0 if denied */ static int -check_allowed_connect_ports(int port) +check_allowed_connect_ports (int port) { - size_t i; - int *data; - - /* - * A port list is REQUIRED for a CONNECT request to function - * properly. This closes a potential security hole. - */ - if (!ports_allowed_by_connect) - return 0; - - for (i = 0; i != vector_length(ports_allowed_by_connect); ++i) { - data = vector_getentry(ports_allowed_by_connect, i, NULL); - if (data && *data == port) - return 1; - } - - return 0; + size_t i; + int *data; + + /* + * A port list is REQUIRED for a CONNECT request to function + * properly. This closes a potential security hole. + */ + if (!ports_allowed_by_connect) + return 0; + + for (i = 0; i != vector_length (ports_allowed_by_connect); ++i) + { + data = vector_getentry (ports_allowed_by_connect, i, NULL); + if (data && *data == port) + return 1; + } + + return 0; } /* @@ -131,57 +134,59 @@ check_allowed_connect_ports(int port) * be freed in another function. */ static int -read_request_line(struct conn_s *connptr) +read_request_line (struct conn_s *connptr) { - ssize_t len; - - retry: - len = readline(connptr->client_fd, &connptr->request_line); - if (len <= 0) { - log_message(LOG_ERR, - "read_request_line: Client (file descriptor: %d) closed socket before read.", - connptr->client_fd); - - return -1; - } - - /* - * Strip the new line and carriage return from the string. - */ - if (chomp(connptr->request_line, len) == len) { - /* - * If the number of characters removed is the same as the - * length then it was a blank line. Free the buffer and - * try again (since we're looking for a request line.) - */ - safefree(connptr->request_line); - goto retry; - } - - log_message(LOG_CONN, "Request (file descriptor %d): %s", - connptr->client_fd, connptr->request_line); - - return 0; + ssize_t len; + +retry: + len = readline (connptr->client_fd, &connptr->request_line); + if (len <= 0) + { + log_message (LOG_ERR, + "read_request_line: Client (file descriptor: %d) closed socket before read.", + connptr->client_fd); + + return -1; + } + + /* + * Strip the new line and carriage return from the string. + */ + if (chomp (connptr->request_line, len) == len) + { + /* + * If the number of characters removed is the same as the + * length then it was a blank line. Free the buffer and + * try again (since we're looking for a request line.) + */ + safefree (connptr->request_line); + goto retry; + } + + log_message (LOG_CONN, "Request (file descriptor %d): %s", + connptr->client_fd, connptr->request_line); + + return 0; } /* * Free all the memory allocated in a request. */ static void -free_request_struct(struct request_s *request) +free_request_struct (struct request_s *request) { - if (!request) - return; + if (!request) + return; - safefree(request->method); - safefree(request->protocol); + safefree (request->method); + safefree (request->protocol); - if (request->host) - safefree(request->host); - if (request->path) - safefree(request->path); + if (request->host) + safefree (request->host); + if (request->path) + safefree (request->path); - safefree(request); + safefree (request); } /* @@ -189,24 +194,24 @@ free_request_struct(struct request_s *request) * it off. */ static void -strip_username_password(char *host) +strip_username_password (char *host) { - char *p; - - assert(host); - assert(strlen(host) > 0); - - if ((p = strchr(host, '@')) == NULL) - return; - - /* - * Move the pointer past the "@" and then copy from that point - * until the NUL to the beginning of the host buffer. - */ - p++; - while (*p) - *host++ = *p++; - *host = '\0'; + char *p; + + assert (host); + assert (strlen (host) > 0); + + if ((p = strchr (host, '@')) == NULL) + return; + + /* + * Move the pointer past the "@" and then copy from that point + * until the NUL to the beginning of the host buffer. + */ + p++; + while (*p) + *host++ = *p++; + *host = '\0'; } /* @@ -214,19 +219,19 @@ strip_username_password(char *host) * it off and set proper port variable i.e. for www.host.com:8001 */ static int -strip_return_port(char *host) +strip_return_port (char *host) { - char *ptr1; - int port; + char *ptr1; + int port; - ptr1 = strchr(host, ':'); - if (ptr1 == NULL) - return 0; + ptr1 = strchr (host, ':'); + if (ptr1 == NULL) + return 0; - *ptr1++ = '\0'; - if (sscanf(ptr1, "%d", &port) != 1) /* one conversion required */ - return 0; - return port; + *ptr1++ = '\0'; + if (sscanf (ptr1, "%d", &port) != 1) /* one conversion required */ + return 0; + return port; } /* @@ -234,70 +239,74 @@ strip_return_port(char *host) * and FTP (proxied) URLs. */ static int -extract_http_url(const char *url, struct request_s *request) +extract_http_url (const char *url, struct request_s *request) { - char *p; - int len; - int port; - - /* Split the URL on the slash to separate host from path */ - p = strchr(url, '/'); - if (p != NULL) { - len = p - url; - request->host = safemalloc(len + 1); - memcpy(request->host, url, len); - request->host[len] = '\0'; - request->path = safestrdup(p); - } else { - request->host = safestrdup(url); - request->path = safestrdup("/"); - } - - if (!request->host || !request->path) - goto ERROR_EXIT; - - /* Remove the username/password if they're present */ - strip_username_password(request->host); - - /* Find a proper port in www.site.com:8001 URLs */ - port = strip_return_port(request->host); - request->port = (port != 0) ? port : HTTP_PORT; - - return 0; - - ERROR_EXIT: - if (request->host) - safefree(request->host); - if (request->path) - safefree(request->path); - - return -1; + char *p; + int len; + int port; + + /* Split the URL on the slash to separate host from path */ + p = strchr (url, '/'); + if (p != NULL) + { + len = p - url; + request->host = safemalloc (len + 1); + memcpy (request->host, url, len); + request->host[len] = '\0'; + request->path = safestrdup (p); + } + else + { + request->host = safestrdup (url); + request->path = safestrdup ("/"); + } + + if (!request->host || !request->path) + goto ERROR_EXIT; + + /* Remove the username/password if they're present */ + strip_username_password (request->host); + + /* Find a proper port in www.site.com:8001 URLs */ + port = strip_return_port (request->host); + request->port = (port != 0) ? port : HTTP_PORT; + + return 0; + +ERROR_EXIT: + if (request->host) + safefree (request->host); + if (request->path) + safefree (request->path); + + return -1; } /* * Extract the URL from a SSL connection. */ static int -extract_ssl_url(const char *url, struct request_s *request) +extract_ssl_url (const char *url, struct request_s *request) { - request->host = safemalloc(strlen(url) + 1); - if (!request->host) - return -1; + request->host = safemalloc (strlen (url) + 1); + if (!request->host) + return -1; - if (sscanf(url, "%[^:]:%hu", request->host, &request->port) == 2) ; - else if (sscanf(url, "%s", request->host) == 1) - request->port = HTTP_PORT_SSL; - else { - log_message(LOG_ERR, "extract_ssl_url: Can't parse URL."); + if (sscanf (url, "%[^:]:%hu", request->host, &request->port) == 2); + else if (sscanf (url, "%s", request->host) == 1) + request->port = HTTP_PORT_SSL; + else + { + log_message (LOG_ERR, "extract_ssl_url: Can't parse URL."); - safefree(request->host); - return -1; - } + safefree (request->host); + return -1; + } - /* Remove the username/password if they're present */ - strip_username_password(request->host); + /* Remove the username/password if they're present */ + strip_username_password (request->host); - return 0; + return 0; } @@ -306,161 +315,183 @@ extract_ssl_url(const char *url, struct request_s *request) * Add an entry to the upstream list */ void -upstream_add(const char *host, int port, const char *domain) +upstream_add (const char *host, int port, const char *domain) { - char *ptr; - struct upstream *up = safemalloc(sizeof(struct upstream)); - - if (!up) { - log_message(LOG_ERR, - "Unable to allocate memory in upstream_add()"); - return; - } - - up->host = up->domain = NULL; - up->ip = up->mask = 0; - - if (domain == NULL) { - if (!host || host[0] == '\0' || port < 1) { - log_message(LOG_WARNING, - "Nonsense upstream rule: invalid host or port"); - goto upstream_cleanup; - } - - up->host = safestrdup(host); - up->port = port; - - log_message(LOG_INFO, "Added upstream %s:%d for [default]", - host, port); - } else if (host == NULL) { - if (!domain || domain[0] == '\0') { - log_message(LOG_WARNING, - "Nonsense no-upstream rule: empty domain"); - goto upstream_cleanup; - } - - ptr = strchr(domain, '/'); - if (ptr) { - struct in_addr addrstruct; - - *ptr = '\0'; - if (inet_aton(domain, &addrstruct) != 0) { - up->ip = ntohl(addrstruct.s_addr); - *ptr++ = '/'; - - if (strchr(ptr, '.')) { - if (inet_aton(ptr, &addrstruct) != 0) - up->mask = - ntohl(addrstruct.s_addr); - } else { - up->mask = - ~((1 << (32 - atoi(ptr))) - 1); - } - } - } else { - up->domain = safestrdup(domain); - } - - log_message(LOG_INFO, "Added no-upstream for %s", domain); - } else { - if (!host || host[0] == '\0' || port < 1 || !domain - || domain == '\0') { - log_message(LOG_WARNING, - "Nonsense upstream rule: invalid parameters"); - goto upstream_cleanup; - } - - up->host = safestrdup(host); - up->port = port; - up->domain = safestrdup(domain); - - log_message(LOG_INFO, "Added upstream %s:%d for %s", - host, port, domain); - } - - if (!up->domain && !up->ip) { /* always add default to end */ - struct upstream *tmp = config.upstream_list; - - while (tmp) { - if (!tmp->domain && !tmp->ip) { - log_message(LOG_WARNING, - "Duplicate default upstream"); - goto upstream_cleanup; - } - - if (!tmp->next) { - up->next = NULL; - tmp->next = up; - return; - } - - tmp = tmp->next; - } - } - - up->next = config.upstream_list; - config.upstream_list = up; - - return; - - upstream_cleanup: - safefree(up->host); - safefree(up->domain); - safefree(up); - - return; + char *ptr; + struct upstream *up = safemalloc (sizeof (struct upstream)); + + if (!up) + { + log_message (LOG_ERR, "Unable to allocate memory in upstream_add()"); + return; + } + + up->host = up->domain = NULL; + up->ip = up->mask = 0; + + if (domain == NULL) + { + if (!host || host[0] == '\0' || port < 1) + { + log_message (LOG_WARNING, + "Nonsense upstream rule: invalid host or port"); + goto upstream_cleanup; + } + + up->host = safestrdup (host); + up->port = port; + + log_message (LOG_INFO, "Added upstream %s:%d for [default]", + host, port); + } + else if (host == NULL) + { + if (!domain || domain[0] == '\0') + { + log_message (LOG_WARNING, + "Nonsense no-upstream rule: empty domain"); + goto upstream_cleanup; + } + + ptr = strchr (domain, '/'); + if (ptr) + { + struct in_addr addrstruct; + + *ptr = '\0'; + if (inet_aton (domain, &addrstruct) != 0) + { + up->ip = ntohl (addrstruct.s_addr); + *ptr++ = '/'; + + if (strchr (ptr, '.')) + { + if (inet_aton (ptr, &addrstruct) != 0) + up->mask = ntohl (addrstruct.s_addr); + } + else + { + up->mask = ~((1 << (32 - atoi (ptr))) - 1); + } + } + } + else + { + up->domain = safestrdup (domain); + } + + log_message (LOG_INFO, "Added no-upstream for %s", domain); + } + else + { + if (!host || host[0] == '\0' || port < 1 || !domain || domain == '\0') + { + log_message (LOG_WARNING, + "Nonsense upstream rule: invalid parameters"); + goto upstream_cleanup; + } + + up->host = safestrdup (host); + up->port = port; + up->domain = safestrdup (domain); + + log_message (LOG_INFO, "Added upstream %s:%d for %s", + host, port, domain); + } + + if (!up->domain && !up->ip) + { /* always add default to end */ + struct upstream *tmp = config.upstream_list; + + while (tmp) + { + if (!tmp->domain && !tmp->ip) + { + log_message (LOG_WARNING, "Duplicate default upstream"); + goto upstream_cleanup; + } + + if (!tmp->next) + { + up->next = NULL; + tmp->next = up; + return; + } + + tmp = tmp->next; + } + } + + up->next = config.upstream_list; + config.upstream_list = up; + + return; + +upstream_cleanup: + safefree (up->host); + safefree (up->domain); + safefree (up); + + return; } /* * Check if a host is in the upstream list */ static struct upstream * -upstream_get(char *host) +upstream_get (char *host) { - struct upstream *up = config.upstream_list; - - in_addr_t my_ip = INADDR_NONE; - - while (up) { - if (up->domain) { - if (strcasecmp(host, up->domain) == 0) - break; /* exact match */ - - if (up->domain[0] == '.') { - char *dot = strchr(host, '.'); - - if (!dot && !up->domain[1]) - break; /* local host matches "." */ - - while (dot && strcasecmp(dot, up->domain)) - dot = strchr(dot + 1, '.'); - - if (dot) - break; /* subdomain match */ - } - } else if (up->ip) { - if (my_ip == INADDR_NONE) - my_ip = ntohl(inet_addr(host)); - - if ((my_ip & up->mask) == up->ip) - break; - } else { - break; /* No domain or IP, default upstream */ - } - - up = up->next; - } - - if (up && (!up->host || !up->port)) - up = NULL; - - if (up) - log_message(LOG_INFO, "Found proxy %s:%d for %s", - up->host, up->port, host); - else - log_message(LOG_INFO, "No proxy for %s", host); - - return up; + struct upstream *up = config.upstream_list; + + in_addr_t my_ip = INADDR_NONE; + + while (up) + { + if (up->domain) + { + if (strcasecmp (host, up->domain) == 0) + break; /* exact match */ + + if (up->domain[0] == '.') + { + char *dot = strchr (host, '.'); + + if (!dot && !up->domain[1]) + break; /* local host matches "." */ + + while (dot && strcasecmp (dot, up->domain)) + dot = strchr (dot + 1, '.'); + + if (dot) + break; /* subdomain match */ + } + } + else if (up->ip) + { + if (my_ip == INADDR_NONE) + my_ip = ntohl (inet_addr (host)); + + if ((my_ip & up->mask) == up->ip) + break; + } + else + { + break; /* No domain or IP, default upstream */ + } + + up = up->next; + } + + if (up && (!up->host || !up->port)) + up = NULL; + + if (up) + log_message (LOG_INFO, "Found proxy %s:%d for %s", + up->host, up->port, host); + else + log_message (LOG_INFO, "No proxy for %s", host); + + return up; } #endif @@ -468,22 +499,22 @@ upstream_get(char *host) * Create a connection for HTTP connections. */ static int -establish_http_connection(struct conn_s *connptr, struct request_s *request) +establish_http_connection (struct conn_s *connptr, struct request_s *request) { - char portbuff[7]; - - /* Build a port string if it's not a standard port */ - if (request->port != HTTP_PORT && request->port != HTTP_PORT_SSL) - snprintf(portbuff, 7, ":%u", request->port); - else - portbuff[0] = '\0'; - - return write_message(connptr->server_fd, - "%s %s HTTP/1.0\r\n" - "Host: %s%s\r\n" - "Connection: close\r\n", - request->method, request->path, - request->host, portbuff); + char portbuff[7]; + + /* Build a port string if it's not a standard port */ + if (request->port != HTTP_PORT && request->port != HTTP_PORT_SSL) + snprintf (portbuff, 7, ":%u", request->port); + else + portbuff[0] = '\0'; + + return write_message (connptr->server_fd, + "%s %s HTTP/1.0\r\n" + "Host: %s%s\r\n" + "Connection: close\r\n", + request->method, request->path, + request->host, portbuff); } /* @@ -497,12 +528,12 @@ establish_http_connection(struct conn_s *connptr, struct request_s *request) * connection. */ static inline int -send_ssl_response(struct conn_s *connptr) +send_ssl_response (struct conn_s *connptr) { - return write_message(connptr->client_fd, - "%s\r\n" - "%s\r\n" - "\r\n", SSL_CONNECTION_RESPONSE, PROXY_AGENT); + return write_message (connptr->client_fd, + "%s\r\n" + "%s\r\n" + "\r\n", SSL_CONNECTION_RESPONSE, PROXY_AGENT); } /* @@ -510,218 +541,239 @@ send_ssl_response(struct conn_s *connptr) * build a new request line. Finally connect to the remote server. */ static struct request_s * -process_request(struct conn_s *connptr, hashmap_t hashofheaders) +process_request (struct conn_s *connptr, hashmap_t hashofheaders) { - char *url; - struct request_s *request; - int ret; - size_t request_len; - - /* NULL out all the fields so frees don't cause segfaults. */ - request = safecalloc(1, sizeof(struct request_s)); - if (!request) - return NULL; - - request_len = strlen(connptr->request_line) + 1; - - request->method = safemalloc(request_len); - url = safemalloc(request_len); - request->protocol = safemalloc(request_len); - - if (!request->method || !url || !request->protocol) { - safefree(url); - free_request_struct(request); - - return NULL; - } - - ret = sscanf(connptr->request_line, "%[^ ] %[^ ] %[^ ]", - request->method, url, request->protocol); - if (ret == 2 && !strcasecmp(request->method, "GET")) { - request->protocol[0] = 0; - - /* Indicate that this is a HTTP/0.9 GET request */ - connptr->protocol.major = 0; - connptr->protocol.minor = 9; - } else if (ret == 3 && !strncasecmp(request->protocol, "HTTP/", 5)) { - /* - * Break apart the protocol and update the connection - * structure. - */ - ret = sscanf(request->protocol + 5, "%u.%u", - &connptr->protocol.major, - &connptr->protocol.minor); - - /* - * If the conversion doesn't succeed, drop down below and - * send the error to the user. - */ - if (ret != 2) - goto BAD_REQUEST_ERROR; - } else { - BAD_REQUEST_ERROR: - log_message(LOG_ERR, - "process_request: Bad Request on file descriptor %d", - connptr->client_fd); - indicate_http_error(connptr, 400, "Bad Request", - "detail", "Request has an invalid format", - "url", url, NULL); - - safefree(url); - free_request_struct(request); - - return NULL; - } - - if (!url) { - log_message(LOG_ERR, - "process_request: Null URL on file descriptor %d", - connptr->client_fd); - indicate_http_error(connptr, 400, "Bad Request", - "detail", "Request has an empty URL", - "url", url, NULL); - - safefree(url); - free_request_struct(request); - - return NULL; - } + char *url; + struct request_s *request; + int ret; + size_t request_len; + + /* NULL out all the fields so frees don't cause segfaults. */ + request = safecalloc (1, sizeof (struct request_s)); + if (!request) + return NULL; + + request_len = strlen (connptr->request_line) + 1; + + request->method = safemalloc (request_len); + url = safemalloc (request_len); + request->protocol = safemalloc (request_len); + + if (!request->method || !url || !request->protocol) + { + safefree (url); + free_request_struct (request); + + return NULL; + } + + ret = sscanf (connptr->request_line, "%[^ ] %[^ ] %[^ ]", + request->method, url, request->protocol); + if (ret == 2 && !strcasecmp (request->method, "GET")) + { + request->protocol[0] = 0; + + /* Indicate that this is a HTTP/0.9 GET request */ + connptr->protocol.major = 0; + connptr->protocol.minor = 9; + } + else if (ret == 3 && !strncasecmp (request->protocol, "HTTP/", 5)) + { + /* + * Break apart the protocol and update the connection + * structure. + */ + ret = sscanf (request->protocol + 5, "%u.%u", + &connptr->protocol.major, &connptr->protocol.minor); + + /* + * If the conversion doesn't succeed, drop down below and + * send the error to the user. + */ + if (ret != 2) + goto BAD_REQUEST_ERROR; + } + else + { + BAD_REQUEST_ERROR: + log_message (LOG_ERR, + "process_request: Bad Request on file descriptor %d", + connptr->client_fd); + indicate_http_error (connptr, 400, "Bad Request", + "detail", "Request has an invalid format", + "url", url, NULL); + + safefree (url); + free_request_struct (request); + + return NULL; + } + + if (!url) + { + log_message (LOG_ERR, + "process_request: Null URL on file descriptor %d", + connptr->client_fd); + indicate_http_error (connptr, 400, "Bad Request", + "detail", "Request has an empty URL", + "url", url, NULL); + + safefree (url); + free_request_struct (request); + + return NULL; + } #ifdef REVERSE_SUPPORT - if (config.reversepath_list != NULL) { - /* - * Rewrite the URL based on the reverse path. After calling - * reverse_rewrite_url "url" can be freed since we either - * have the newly rewritten URL, or something failed and - * we'll be closing anyway. - */ - char *reverse_url; - - reverse_url = reverse_rewrite_url(connptr, hashofheaders, url); - safefree(url); - - if (!reverse_url) { - free_request_struct(request); - return NULL; - } else { - url = reverse_url; - } - } + if (config.reversepath_list != NULL) + { + /* + * Rewrite the URL based on the reverse path. After calling + * reverse_rewrite_url "url" can be freed since we either + * have the newly rewritten URL, or something failed and + * we'll be closing anyway. + */ + char *reverse_url; + + reverse_url = reverse_rewrite_url (connptr, hashofheaders, url); + safefree (url); + + if (!reverse_url) + { + free_request_struct (request); + return NULL; + } + else + { + url = reverse_url; + } + } #endif - if (strncasecmp(url, "http://", 7) == 0 - || (UPSTREAM_CONFIGURED() && strncasecmp(url, "ftp://", 6) == 0)) { - char *skipped_type = strstr(url, "//") + 2; - - if (extract_http_url(skipped_type, request) < 0) { - indicate_http_error(connptr, 400, "Bad Request", - "detail", "Could not parse URL", - "url", url, NULL); - - safefree(url); - free_request_struct(request); - - return NULL; - } - } else if (strcmp(request->method, "CONNECT") == 0) { - if (extract_ssl_url(url, request) < 0) { - indicate_http_error(connptr, 400, "Bad Request", - "detail", "Could not parse URL", - "url", url, NULL); - - safefree(url); - free_request_struct(request); - - return NULL; - } - - /* Verify that the port in the CONNECT method is allowed */ - if (!check_allowed_connect_ports(request->port)) { - indicate_http_error(connptr, 403, "Access violation", - "detail", - "The CONNECT method not allowed " - "with the port you tried to use.", - "url", url, NULL); - log_message(LOG_INFO, - "Refused CONNECT method on port %d", - request->port); - - safefree(url); - free_request_struct(request); - - return NULL; - } - - connptr->connect_method = TRUE; - } else { + if (strncasecmp (url, "http://", 7) == 0 + || (UPSTREAM_CONFIGURED () && strncasecmp (url, "ftp://", 6) == 0)) + { + char *skipped_type = strstr (url, "//") + 2; + + if (extract_http_url (skipped_type, request) < 0) + { + indicate_http_error (connptr, 400, "Bad Request", + "detail", "Could not parse URL", + "url", url, NULL); + + safefree (url); + free_request_struct (request); + + return NULL; + } + } + else if (strcmp (request->method, "CONNECT") == 0) + { + if (extract_ssl_url (url, request) < 0) + { + indicate_http_error (connptr, 400, "Bad Request", + "detail", "Could not parse URL", + "url", url, NULL); + + safefree (url); + free_request_struct (request); + + return NULL; + } + + /* Verify that the port in the CONNECT method is allowed */ + if (!check_allowed_connect_ports (request->port)) + { + indicate_http_error (connptr, 403, "Access violation", + "detail", + "The CONNECT method not allowed " + "with the port you tried to use.", + "url", url, NULL); + log_message (LOG_INFO, + "Refused CONNECT method on port %d", request->port); + + safefree (url); + free_request_struct (request); + + return NULL; + } + + connptr->connect_method = TRUE; + } + else + { #ifdef TRANSPARENT_PROXY - if (!do_transparent_proxy(connptr, hashofheaders, request, &config, url)) { - safefree(url); - free_request_struct(request); - return NULL; - } + if (!do_transparent_proxy + (connptr, hashofheaders, request, &config, url)) + { + safefree (url); + free_request_struct (request); + return NULL; + } #else - indicate_http_error(connptr, 501, "Not Implemented", - "detail", "Unknown method or unsupported protocol.", - "url", url, NULL); - log_message(LOG_INFO, - "Unknown method (%s) or protocol (%s)", - request->method, url); - safefree(url); - free_request_struct(request); - return NULL; - + indicate_http_error (connptr, 501, "Not Implemented", + "detail", + "Unknown method or unsupported protocol.", "url", + url, NULL); + log_message (LOG_INFO, "Unknown method (%s) or protocol (%s)", + request->method, url); + safefree (url); + free_request_struct (request); + return NULL; + #endif - } + } #ifdef FILTER_ENABLE - /* - * Filter restricted domains/urls - */ - if (config.filter) { - if (config.filter_url) - ret = filter_url(url); - else - ret = filter_domain(request->host); - - if (ret) { - update_stats(STAT_DENIED); - - if (config.filter_url) - log_message(LOG_NOTICE, - "Proxying refused on filtered url \"%s\"", - url); - else - log_message(LOG_NOTICE, - "Proxying refused on filtered domain \"%s\"", - request->host); - - indicate_http_error(connptr, 403, "Filtered", - "detail", - "The request you made has been filtered", - "url", url, NULL); - - safefree(url); - free_request_struct(request); - - return NULL; - } - } + /* + * Filter restricted domains/urls + */ + if (config.filter) + { + if (config.filter_url) + ret = filter_url (url); + else + ret = filter_domain (request->host); + + if (ret) + { + update_stats (STAT_DENIED); + + if (config.filter_url) + log_message (LOG_NOTICE, + "Proxying refused on filtered url \"%s\"", url); + else + log_message (LOG_NOTICE, + "Proxying refused on filtered domain \"%s\"", + request->host); + + indicate_http_error (connptr, 403, "Filtered", + "detail", + "The request you made has been filtered", + "url", url, NULL); + + safefree (url); + free_request_struct (request); + + return NULL; + } + } #endif - safefree(url); + safefree (url); - /* - * Check to see if they're requesting the stat host - */ - if (config.stathost && strcmp(config.stathost, request->host) == 0) { - log_message(LOG_NOTICE, "Request for the stathost."); - connptr->show_stats = TRUE; + /* + * Check to see if they're requesting the stat host + */ + if (config.stathost && strcmp (config.stathost, request->host) == 0) + { + log_message (LOG_NOTICE, "Request for the stathost."); + connptr->show_stats = TRUE; - free_request_struct(request); - return NULL; - } + free_request_struct (request); + return NULL; + } - return request; + return request; } /* @@ -731,50 +783,52 @@ process_request(struct conn_s *connptr, hashmap_t hashofheaders) * - rjkaes */ static int -pull_client_data(struct conn_s *connptr, long int length) +pull_client_data (struct conn_s *connptr, long int length) { - char *buffer; - ssize_t len; - - buffer = safemalloc(min(MAXBUFFSIZE, length)); - if (!buffer) - return -1; - - do { - len = safe_read(connptr->client_fd, buffer, - min(MAXBUFFSIZE, length)); - if (len <= 0) - goto ERROR_EXIT; - - if (!connptr->error_variables) { - if (safe_write(connptr->server_fd, buffer, len) < 0) - goto ERROR_EXIT; - } - - length -= len; - } while (length > 0); - - /* - * BUG FIX: Internet Explorer will leave two bytes (carriage - * return and line feed) at the end of a POST message. These - * need to be eaten for tinyproxy to work correctly. - */ - socket_nonblocking(connptr->client_fd); - len = recv(connptr->client_fd, buffer, 2, MSG_PEEK); - socket_blocking(connptr->client_fd); - - if (len < 0 && errno != EAGAIN) - goto ERROR_EXIT; - - if (len == 2 && CHECK_CRLF(buffer, len)) - read(connptr->client_fd, buffer, 2); - - safefree(buffer); - return 0; - - ERROR_EXIT: - safefree(buffer); - return -1; + char *buffer; + ssize_t len; + + buffer = safemalloc (min (MAXBUFFSIZE, length)); + if (!buffer) + return -1; + + do + { + len = safe_read (connptr->client_fd, buffer, min (MAXBUFFSIZE, length)); + if (len <= 0) + goto ERROR_EXIT; + + if (!connptr->error_variables) + { + if (safe_write (connptr->server_fd, buffer, len) < 0) + goto ERROR_EXIT; + } + + length -= len; + } + while (length > 0); + + /* + * BUG FIX: Internet Explorer will leave two bytes (carriage + * return and line feed) at the end of a POST message. These + * need to be eaten for tinyproxy to work correctly. + */ + socket_nonblocking (connptr->client_fd); + len = recv (connptr->client_fd, buffer, 2, MSG_PEEK); + socket_blocking (connptr->client_fd); + + if (len < 0 && errno != EAGAIN) + goto ERROR_EXIT; + + if (len == 2 && CHECK_CRLF (buffer, len)) + read (connptr->client_fd, buffer, 2); + + safefree (buffer); + return 0; + +ERROR_EXIT: + safefree (buffer); + return -1; } #ifdef XTINYPROXY_ENABLE @@ -784,13 +838,13 @@ pull_client_data(struct conn_s *connptr, long int length) * -rjkaes */ static inline int -add_xtinyproxy_header(struct conn_s *connptr) +add_xtinyproxy_header (struct conn_s *connptr) { - assert(connptr && connptr->server_fd >= 0); - return write_message(connptr->server_fd, - "X-Tinyproxy: %s\r\n", connptr->client_ip_addr); + assert (connptr && connptr->server_fd >= 0); + return write_message (connptr->server_fd, + "X-Tinyproxy: %s\r\n", connptr->client_ip_addr); } -#endif /* XTINYPROXY */ +#endif /* XTINYPROXY */ /* * Take a complete header line and break it apart (into a key and the data.) @@ -798,82 +852,86 @@ add_xtinyproxy_header(struct conn_s *connptr) * can be retrieved and manipulated later. */ static inline int -add_header_to_connection(hashmap_t hashofheaders, char *header, size_t len) +add_header_to_connection (hashmap_t hashofheaders, char *header, size_t len) { - char *sep; + char *sep; - /* Get rid of the new line and return at the end */ - len -= chomp(header, len); + /* Get rid of the new line and return at the end */ + len -= chomp (header, len); - sep = strchr(header, ':'); - if (!sep) - return -1; + sep = strchr (header, ':'); + if (!sep) + return -1; - /* Blank out colons, spaces, and tabs. */ - while (*sep == ':' || *sep == ' ' || *sep == '\t') - *sep++ = '\0'; + /* Blank out colons, spaces, and tabs. */ + while (*sep == ':' || *sep == ' ' || *sep == '\t') + *sep++ = '\0'; - /* Calculate the new length of just the data */ - len -= sep - header - 1; + /* Calculate the new length of just the data */ + len -= sep - header - 1; - return hashmap_insert(hashofheaders, header, sep, len); + return hashmap_insert (hashofheaders, header, sep, len); } /* * Read all the headers from the stream */ static int -get_all_headers(int fd, hashmap_t hashofheaders) +get_all_headers (int fd, hashmap_t hashofheaders) { - char *header; - ssize_t len; - unsigned int double_cgi = FALSE; /* boolean */ - - assert(fd >= 0); - assert(hashofheaders != NULL); - - for (;;) { - if ((len = readline(fd, &header)) <= 0) { - safefree(header); - return -1; - } - - /* - * If we received just a CR LF on a line, the headers are - * finished. - */ - if (CHECK_CRLF(header, len)) { - safefree(header); - return 0; - } - - /* - * BUG FIX: The following code detects a "Double CGI" - * situation so that we can handle the nonconforming system. - * This problem was found when accessing cgi.ebay.com, and it - * turns out to be a wider spread problem as well. - * - * If "Double CGI" is in effect, duplicate headers are - * ignored. - * - * FIXME: Might need to change this to a more robust check. - */ - if (strncasecmp(header, "HTTP/", 5) == 0) { - double_cgi = TRUE; - - safefree(header); - continue; - } - - if (!double_cgi - && add_header_to_connection(hashofheaders, header, - len) < 0) { - safefree(header); - return -1; - } - - safefree(header); - } + char *header; + ssize_t len; + unsigned int double_cgi = FALSE; /* boolean */ + + assert (fd >= 0); + assert (hashofheaders != NULL); + + for (;;) + { + if ((len = readline (fd, &header)) <= 0) + { + safefree (header); + return -1; + } + + /* + * If we received just a CR LF on a line, the headers are + * finished. + */ + if (CHECK_CRLF (header, len)) + { + safefree (header); + return 0; + } + + /* + * BUG FIX: The following code detects a "Double CGI" + * situation so that we can handle the nonconforming system. + * This problem was found when accessing cgi.ebay.com, and it + * turns out to be a wider spread problem as well. + * + * If "Double CGI" is in effect, duplicate headers are + * ignored. + * + * FIXME: Might need to change this to a more robust check. + */ + if (strncasecmp (header, "HTTP/", 5) == 0) + { + double_cgi = TRUE; + + safefree (header); + continue; + } + + if (!double_cgi + && add_header_to_connection (hashofheaders, header, len) < 0) + { + safefree (header); + return -1; + } + + safefree (header); + } } /* @@ -881,53 +939,53 @@ get_all_headers(int fd, hashmap_t hashofheaders) * and Proxy-Connection headers. */ static int -remove_connection_headers(hashmap_t hashofheaders) +remove_connection_headers (hashmap_t hashofheaders) { - static char *headers[] = { - "connection", - "proxy-connection" - }; - - char *data; - char *ptr; - ssize_t len; - int i; - - for (i = 0; i != (sizeof(headers) / sizeof(char *)); ++i) { - /* Look for the connection header. If it's not found, return. */ - len = - hashmap_entry_by_key(hashofheaders, headers[i], - (void **)&data); - if (len <= 0) - return 0; - - /* - * Go through the data line and replace any special characters - * with a NULL. - */ - ptr = data; - while ((ptr = strpbrk(ptr, "()<>@,;:\\\"/[]?={} \t"))) - *ptr++ = '\0'; - - /* - * All the tokens are separated by NULLs. Now go through the - * token and remove them from the hashofheaders. - */ - ptr = data; - while (ptr < data + len) { - hashmap_remove(hashofheaders, ptr); - - /* Advance ptr to the next token */ - ptr += strlen(ptr) + 1; - while (ptr < data + len && *ptr == '\0') - ptr++; - } - - /* Now remove the connection header it self. */ - hashmap_remove(hashofheaders, headers[i]); - } - - return 0; + static char *headers[] = { + "connection", + "proxy-connection" + }; + + char *data; + char *ptr; + ssize_t len; + int i; + + for (i = 0; i != (sizeof (headers) / sizeof (char *)); ++i) + { + /* Look for the connection header. If it's not found, return. */ + len = hashmap_entry_by_key (hashofheaders, headers[i], (void **) &data); + if (len <= 0) + return 0; + + /* + * Go through the data line and replace any special characters + * with a NULL. + */ + ptr = data; + while ((ptr = strpbrk (ptr, "()<>@,;:\\\"/[]?={} \t"))) + *ptr++ = '\0'; + + /* + * All the tokens are separated by NULLs. Now go through the + * token and remove them from the hashofheaders. + */ + ptr = data; + while (ptr < data + len) + { + hashmap_remove (hashofheaders, ptr); + + /* Advance ptr to the next token */ + ptr += strlen (ptr) + 1; + while (ptr < data + len && *ptr == '\0') + ptr++; + } + + /* Now remove the connection header it self. */ + hashmap_remove (hashofheaders, headers[i]); + } + + return 0; } /* @@ -935,19 +993,18 @@ remove_connection_headers(hashmap_t hashofheaders) * a negative number. */ static long -get_content_length(hashmap_t hashofheaders) +get_content_length (hashmap_t hashofheaders) { - ssize_t len; - char *data; - long content_length = -1; + ssize_t len; + char *data; + long content_length = -1; - len = - hashmap_entry_by_key(hashofheaders, "content-length", - (void **)&data); - if (len > 0) - content_length = atol(data); + len = + hashmap_entry_by_key (hashofheaders, "content-length", (void **) &data); + if (len > 0) + content_length = atol (data); - return content_length; + return content_length; } /* @@ -958,39 +1015,44 @@ get_content_length(hashmap_t hashofheaders) * purposes. */ static int -write_via_header(int fd, hashmap_t hashofheaders, - unsigned int major, unsigned int minor) +write_via_header (int fd, hashmap_t hashofheaders, + unsigned int major, unsigned int minor) { - ssize_t len; - char hostname[512]; - char *data; - int ret; - - if (config.via_proxy_name) { - strlcpy(hostname, config.via_proxy_name, sizeof(hostname)); - } else if (gethostname(hostname, sizeof(hostname)) < 0) { - strcpy(hostname, "unknown"); - } - - /* - * See if there is a "Via" header. If so, again we need to do a bit - * of processing. - */ - len = hashmap_entry_by_key(hashofheaders, "via", (void **)&data); - if (len > 0) { - ret = write_message(fd, - "Via: %s, %hu.%hu %s (%s/%s)\r\n", - data, - major, minor, hostname, PACKAGE, VERSION); - - hashmap_remove(hashofheaders, "via"); - } else { - ret = write_message(fd, - "Via: %hu.%hu %s (%s/%s)\r\n", - major, minor, hostname, PACKAGE, VERSION); - } - - return ret; + ssize_t len; + char hostname[512]; + char *data; + int ret; + + if (config.via_proxy_name) + { + strlcpy (hostname, config.via_proxy_name, sizeof (hostname)); + } + else if (gethostname (hostname, sizeof (hostname)) < 0) + { + strcpy (hostname, "unknown"); + } + + /* + * See if there is a "Via" header. If so, again we need to do a bit + * of processing. + */ + len = hashmap_entry_by_key (hashofheaders, "via", (void **) &data); + if (len > 0) + { + ret = write_message (fd, + "Via: %s, %hu.%hu %s (%s/%s)\r\n", + data, major, minor, hostname, PACKAGE, VERSION); + + hashmap_remove (hashofheaders, "via"); + } + else + { + ret = write_message (fd, + "Via: %hu.%hu %s (%s/%s)\r\n", + major, minor, hostname, PACKAGE, VERSION); + } + + return ret; } /* @@ -1005,110 +1067,113 @@ write_via_header(int fd, hashmap_t hashofheaders, * - rjkaes */ static int -process_client_headers(struct conn_s *connptr, hashmap_t hashofheaders) +process_client_headers (struct conn_s *connptr, hashmap_t hashofheaders) { - static char *skipheaders[] = { - "host", - "keep-alive", - "proxy-connection", - "te", - "trailers", - "transfer-encoding", - "upgrade" - }; - int i; - hashmap_iter iter; - int ret = 0; - - char *data, *header; - - /* - * Don't send headers if there's already an error, if the request was - * a stats request, or if this was a CONNECT method (unless upstream - * proxy is in use.) - */ - if (connptr->server_fd == -1 || connptr->show_stats - || (connptr->connect_method && (connptr->upstream_proxy == NULL))) { - log_message(LOG_INFO, - "Not sending client headers to remote machine"); - return 0; - } - - /* - * See if there is a "Content-Length" header. If so, again we need - * to do a bit of processing. - */ - connptr->content_length.client = get_content_length(hashofheaders); - - /* - * See if there is a "Connection" header. If so, we need to do a bit - * of processing. :) - */ - remove_connection_headers(hashofheaders); - - /* - * Delete the headers listed in the skipheaders list - */ - for (i = 0; i != (sizeof(skipheaders) / sizeof(char *)); i++) { - hashmap_remove(hashofheaders, skipheaders[i]); - } - - /* Send, or add the Via header */ - ret = write_via_header(connptr->server_fd, hashofheaders, - connptr->protocol.major, - connptr->protocol.minor); - if (ret < 0) { - indicate_http_error(connptr, 503, - "Could not send data to remote server", - "detail", - "A network error occurred while trying to write data to the remote web server.", - NULL); - goto PULL_CLIENT_DATA; - } - - /* - * Output all the remaining headers to the remote machine. - */ - iter = hashmap_first(hashofheaders); - if (iter >= 0) { - for (; !hashmap_is_end(hashofheaders, iter); ++iter) { - hashmap_return_entry(hashofheaders, - iter, &data, (void **)&header); - - if (!is_anonymous_enabled() - || anonymous_search(data) > 0) { - ret = - write_message(connptr->server_fd, - "%s: %s\r\n", data, header); - if (ret < 0) { - indicate_http_error(connptr, 503, - "Could not send data to remote server", - "detail", - "A network error occurred while trying to write data to the remote web server.", - NULL); - goto PULL_CLIENT_DATA; - } - } - } - } + static char *skipheaders[] = { + "host", + "keep-alive", + "proxy-connection", + "te", + "trailers", + "transfer-encoding", + "upgrade" + }; + int i; + hashmap_iter iter; + int ret = 0; + + char *data, *header; + + /* + * Don't send headers if there's already an error, if the request was + * a stats request, or if this was a CONNECT method (unless upstream + * proxy is in use.) + */ + if (connptr->server_fd == -1 || connptr->show_stats + || (connptr->connect_method && (connptr->upstream_proxy == NULL))) + { + log_message (LOG_INFO, "Not sending client headers to remote machine"); + return 0; + } + + /* + * See if there is a "Content-Length" header. If so, again we need + * to do a bit of processing. + */ + connptr->content_length.client = get_content_length (hashofheaders); + + /* + * See if there is a "Connection" header. If so, we need to do a bit + * of processing. :) + */ + remove_connection_headers (hashofheaders); + + /* + * Delete the headers listed in the skipheaders list + */ + for (i = 0; i != (sizeof (skipheaders) / sizeof (char *)); i++) + { + hashmap_remove (hashofheaders, skipheaders[i]); + } + + /* Send, or add the Via header */ + ret = write_via_header (connptr->server_fd, hashofheaders, + connptr->protocol.major, connptr->protocol.minor); + if (ret < 0) + { + indicate_http_error (connptr, 503, + "Could not send data to remote server", + "detail", + "A network error occurred while trying to write data to the remote web server.", + NULL); + goto PULL_CLIENT_DATA; + } + + /* + * Output all the remaining headers to the remote machine. + */ + iter = hashmap_first (hashofheaders); + if (iter >= 0) + { + for (; !hashmap_is_end (hashofheaders, iter); ++iter) + { + hashmap_return_entry (hashofheaders, + iter, &data, (void **) &header); + + if (!is_anonymous_enabled () || anonymous_search (data) > 0) + { + ret = + write_message (connptr->server_fd, + "%s: %s\r\n", data, header); + if (ret < 0) + { + indicate_http_error (connptr, 503, + "Could not send data to remote server", + "detail", + "A network error occurred while trying to write data to the remote web server.", + NULL); + goto PULL_CLIENT_DATA; + } + } + } + } #if defined(XTINYPROXY_ENABLE) - if (config.my_domain) - add_xtinyproxy_header(connptr); + if (config.my_domain) + add_xtinyproxy_header (connptr); #endif - /* Write the final "blank" line to signify the end of the headers */ - if (safe_write(connptr->server_fd, "\r\n", 2) < 0) - return -1; - - /* - * Spin here pulling the data from the client. - */ - PULL_CLIENT_DATA: - if (connptr->content_length.client > 0) - return pull_client_data(connptr, - connptr->content_length.client); - else - return ret; + /* Write the final "blank" line to signify the end of the headers */ + if (safe_write (connptr->server_fd, "\r\n", 2) < 0) + return -1; + + /* + * Spin here pulling the data from the client. + */ +PULL_CLIENT_DATA: + if (connptr->content_length.client > 0) + return pull_client_data (connptr, connptr->content_length.client); + else + return ret; } /* @@ -1116,184 +1181,192 @@ process_client_headers(struct conn_s *connptr, hashmap_t hashofheaders) * server. */ static int -process_server_headers(struct conn_s *connptr) +process_server_headers (struct conn_s *connptr) { - static char *skipheaders[] = { - "keep-alive", - "proxy-authenticate", - "proxy-authorization", - "proxy-connection", - "transfer-encoding", - }; - - char *response_line; - - hashmap_t hashofheaders; - hashmap_iter iter; - char *data, *header; - ssize_t len; - int i; - int ret; + static char *skipheaders[] = { + "keep-alive", + "proxy-authenticate", + "proxy-authorization", + "proxy-connection", + "transfer-encoding", + }; + + char *response_line; + + hashmap_t hashofheaders; + hashmap_iter iter; + char *data, *header; + ssize_t len; + int i; + int ret; #ifdef REVERSE_SUPPORT - struct reversepath *reverse = config.reversepath_list; + struct reversepath *reverse = config.reversepath_list; #endif - /* Get the response line from the remote server. */ - retry: - len = readline(connptr->server_fd, &response_line); - if (len <= 0) - return -1; - - /* - * Strip the new line and character return from the string. - */ - if (chomp(response_line, len) == len) { - /* - * If the number of characters removed is the same as the - * length then it was a blank line. Free the buffer and - * try again (since we're looking for a request line.) - */ - safefree(response_line); - goto retry; - } - - hashofheaders = hashmap_create(HEADER_BUCKETS); - if (!hashofheaders) { - safefree(response_line); - return -1; - } - - /* - * Get all the headers from the remote server in a big hash - */ - if (get_all_headers(connptr->server_fd, hashofheaders) < 0) { - log_message(LOG_WARNING, - "Could not retrieve all the headers from the remote server."); - hashmap_delete(hashofheaders); - safefree(response_line); - - indicate_http_error(connptr, 503, - "Could not retrieve all the headers", - "detail", - PACKAGE - " was unable to retrieve and process headers from the remote web server.", - NULL); - return -1; - } - - /* - * At this point we've received the response line and all the - * headers. However, if this is a simple HTTP/0.9 request we - * CAN NOT send any of that information back to the client. - * Instead we'll free all the memory and return. - */ - if (connptr->protocol.major < 1) { - hashmap_delete(hashofheaders); - safefree(response_line); - return 0; - } - - /* Send the saved response line first */ - ret = write_message(connptr->client_fd, "%s\r\n", response_line); - safefree(response_line); - if (ret < 0) - goto ERROR_EXIT; - - /* - * If there is a "Content-Length" header, retrieve the information - * from it for later use. - */ - connptr->content_length.server = get_content_length(hashofheaders); - - /* - * See if there is a connection header. If so, we need to to a bit of - * processing. - */ - remove_connection_headers(hashofheaders); - - /* - * Delete the headers listed in the skipheaders list - */ - for (i = 0; i != (sizeof(skipheaders) / sizeof(char *)); i++) { - hashmap_remove(hashofheaders, skipheaders[i]); - } - - /* Send, or add the Via header */ - ret = write_via_header(connptr->client_fd, hashofheaders, - connptr->protocol.major, - connptr->protocol.minor); - if (ret < 0) - goto ERROR_EXIT; + /* Get the response line from the remote server. */ +retry: + len = readline (connptr->server_fd, &response_line); + if (len <= 0) + return -1; + + /* + * Strip the new line and character return from the string. + */ + if (chomp (response_line, len) == len) + { + /* + * If the number of characters removed is the same as the + * length then it was a blank line. Free the buffer and + * try again (since we're looking for a request line.) + */ + safefree (response_line); + goto retry; + } + + hashofheaders = hashmap_create (HEADER_BUCKETS); + if (!hashofheaders) + { + safefree (response_line); + return -1; + } + + /* + * Get all the headers from the remote server in a big hash + */ + if (get_all_headers (connptr->server_fd, hashofheaders) < 0) + { + log_message (LOG_WARNING, + "Could not retrieve all the headers from the remote server."); + hashmap_delete (hashofheaders); + safefree (response_line); + + indicate_http_error (connptr, 503, + "Could not retrieve all the headers", + "detail", + PACKAGE + " was unable to retrieve and process headers from the remote web server.", + NULL); + return -1; + } + + /* + * At this point we've received the response line and all the + * headers. However, if this is a simple HTTP/0.9 request we + * CAN NOT send any of that information back to the client. + * Instead we'll free all the memory and return. + */ + if (connptr->protocol.major < 1) + { + hashmap_delete (hashofheaders); + safefree (response_line); + return 0; + } + + /* Send the saved response line first */ + ret = write_message (connptr->client_fd, "%s\r\n", response_line); + safefree (response_line); + if (ret < 0) + goto ERROR_EXIT; + + /* + * If there is a "Content-Length" header, retrieve the information + * from it for later use. + */ + connptr->content_length.server = get_content_length (hashofheaders); + + /* + * See if there is a connection header. If so, we need to to a bit of + * processing. + */ + remove_connection_headers (hashofheaders); + + /* + * Delete the headers listed in the skipheaders list + */ + for (i = 0; i != (sizeof (skipheaders) / sizeof (char *)); i++) + { + hashmap_remove (hashofheaders, skipheaders[i]); + } + + /* Send, or add the Via header */ + ret = write_via_header (connptr->client_fd, hashofheaders, + connptr->protocol.major, connptr->protocol.minor); + if (ret < 0) + goto ERROR_EXIT; #ifdef REVERSE_SUPPORT - /* Write tracking cookie for the magical reverse proxy path hack */ - if (config.reversemagic && connptr->reversepath) { - ret = write_message(connptr->client_fd, - "Set-Cookie: " REVERSE_COOKIE - "=%s; path=/\r\n", connptr->reversepath); - if (ret < 0) - goto ERROR_EXIT; - } - - /* Rewrite the HTTP redirect if needed */ - if (config.reversebaseurl && - hashmap_entry_by_key(hashofheaders, "location", - (void **)&header) > 0) { - - /* Look for a matching entry in the reversepath list */ - while (reverse) { - if (strncasecmp(header, - reverse->url, - (len = strlen(reverse->url))) == 0) - break; - reverse = reverse->next; - } - - if (reverse) { - ret = - write_message(connptr->client_fd, - "Location: %s%s%s\r\n", - config.reversebaseurl, - (reverse->path + 1), (header + len)); - if (ret < 0) - goto ERROR_EXIT; - - log_message(LOG_INFO, - "Rewriting HTTP redirect: %s -> %s%s%s", - header, config.reversebaseurl, - (reverse->path + 1), (header + len)); - hashmap_remove(hashofheaders, "location"); - } - } + /* Write tracking cookie for the magical reverse proxy path hack */ + if (config.reversemagic && connptr->reversepath) + { + ret = write_message (connptr->client_fd, + "Set-Cookie: " REVERSE_COOKIE + "=%s; path=/\r\n", connptr->reversepath); + if (ret < 0) + goto ERROR_EXIT; + } + + /* Rewrite the HTTP redirect if needed */ + if (config.reversebaseurl && + hashmap_entry_by_key (hashofheaders, "location", (void **) &header) > 0) + { + + /* Look for a matching entry in the reversepath list */ + while (reverse) + { + if (strncasecmp (header, + reverse->url, (len = strlen (reverse->url))) == 0) + break; + reverse = reverse->next; + } + + if (reverse) + { + ret = + write_message (connptr->client_fd, + "Location: %s%s%s\r\n", + config.reversebaseurl, + (reverse->path + 1), (header + len)); + if (ret < 0) + goto ERROR_EXIT; + + log_message (LOG_INFO, + "Rewriting HTTP redirect: %s -> %s%s%s", + header, config.reversebaseurl, + (reverse->path + 1), (header + len)); + hashmap_remove (hashofheaders, "location"); + } + } #endif - /* - * All right, output all the remaining headers to the client. - */ - iter = hashmap_first(hashofheaders); - if (iter >= 0) { - for (; !hashmap_is_end(hashofheaders, iter); ++iter) { - hashmap_return_entry(hashofheaders, - iter, &data, (void **)&header); - - ret = write_message(connptr->client_fd, - "%s: %s\r\n", data, header); - if (ret < 0) - goto ERROR_EXIT; - } - } - hashmap_delete(hashofheaders); - - /* Write the final blank line to signify the end of the headers */ - if (safe_write(connptr->client_fd, "\r\n", 2) < 0) - return -1; - - return 0; - - ERROR_EXIT: - hashmap_delete(hashofheaders); - return -1; + /* + * All right, output all the remaining headers to the client. + */ + iter = hashmap_first (hashofheaders); + if (iter >= 0) + { + for (; !hashmap_is_end (hashofheaders, iter); ++iter) + { + hashmap_return_entry (hashofheaders, + iter, &data, (void **) &header); + + ret = write_message (connptr->client_fd, + "%s: %s\r\n", data, header); + if (ret < 0) + goto ERROR_EXIT; + } + } + hashmap_delete (hashofheaders); + + /* Write the final blank line to signify the end of the headers */ + if (safe_write (connptr->client_fd, "\r\n", 2) < 0) + return -1; + + return 0; + +ERROR_EXIT: + hashmap_delete (hashofheaders); + return -1; } /* @@ -1305,186 +1378,204 @@ process_server_headers(struct conn_s *connptr) * - rjkaes */ static void -relay_connection(struct conn_s *connptr) +relay_connection (struct conn_s *connptr) { - fd_set rset, wset; - struct timeval tv; - time_t last_access; - int ret; - double tdiff; - int maxfd = max(connptr->client_fd, connptr->server_fd) + 1; - ssize_t bytes_received; - - socket_nonblocking(connptr->client_fd); - socket_nonblocking(connptr->server_fd); - - last_access = time(NULL); - - for (;;) { - FD_ZERO(&rset); - FD_ZERO(&wset); - - tv.tv_sec = - config.idletimeout - difftime(time(NULL), last_access); - tv.tv_usec = 0; - - if (buffer_size(connptr->sbuffer) > 0) - FD_SET(connptr->client_fd, &wset); - if (buffer_size(connptr->cbuffer) > 0) - FD_SET(connptr->server_fd, &wset); - if (buffer_size(connptr->sbuffer) < MAXBUFFSIZE) - FD_SET(connptr->server_fd, &rset); - if (buffer_size(connptr->cbuffer) < MAXBUFFSIZE) - FD_SET(connptr->client_fd, &rset); - - ret = select(maxfd, &rset, &wset, NULL, &tv); - - if (ret == 0) { - tdiff = difftime(time(NULL), last_access); - if (tdiff > config.idletimeout) { - log_message(LOG_INFO, - "Idle Timeout (after select) as %g > %u.", - tdiff, config.idletimeout); - return; - } else { - continue; - } - } else if (ret < 0) { - log_message(LOG_ERR, - "relay_connection: select() error \"%s\". Closing connection (client_fd:%d, server_fd:%d)", - strerror(errno), connptr->client_fd, - connptr->server_fd); - return; - } else { - /* - * All right, something was actually selected so mark it. - */ - last_access = time(NULL); - } - - if (FD_ISSET(connptr->server_fd, &rset)) { - bytes_received = - read_buffer(connptr->server_fd, connptr->sbuffer); - if (bytes_received < 0) - break; - - connptr->content_length.server -= bytes_received; - if (connptr->content_length.server == 0) - break; - } - if (FD_ISSET(connptr->client_fd, &rset) - && read_buffer(connptr->client_fd, connptr->cbuffer) < 0) { - break; - } - if (FD_ISSET(connptr->server_fd, &wset) - && write_buffer(connptr->server_fd, connptr->cbuffer) < 0) { - break; - } - if (FD_ISSET(connptr->client_fd, &wset) - && write_buffer(connptr->client_fd, connptr->sbuffer) < 0) { - break; - } - } - - /* - * Here the server has closed the connection... write the - * remainder to the client and then exit. - */ - socket_blocking(connptr->client_fd); - while (buffer_size(connptr->sbuffer) > 0) { - if (write_buffer(connptr->client_fd, connptr->sbuffer) < 0) - break; - } - shutdown(connptr->client_fd, SHUT_WR); - - /* - * Try to send any remaining data to the server if we can. - */ - socket_blocking(connptr->server_fd); - while (buffer_size(connptr->cbuffer) > 0) { - if (write_buffer(connptr->server_fd, connptr->cbuffer) < 0) - break; - } - - return; + fd_set rset, wset; + struct timeval tv; + time_t last_access; + int ret; + double tdiff; + int maxfd = max (connptr->client_fd, connptr->server_fd) + 1; + ssize_t bytes_received; + + socket_nonblocking (connptr->client_fd); + socket_nonblocking (connptr->server_fd); + + last_access = time (NULL); + + for (;;) + { + FD_ZERO (&rset); + FD_ZERO (&wset); + + tv.tv_sec = config.idletimeout - difftime (time (NULL), last_access); + tv.tv_usec = 0; + + if (buffer_size (connptr->sbuffer) > 0) + FD_SET (connptr->client_fd, &wset); + if (buffer_size (connptr->cbuffer) > 0) + FD_SET (connptr->server_fd, &wset); + if (buffer_size (connptr->sbuffer) < MAXBUFFSIZE) + FD_SET (connptr->server_fd, &rset); + if (buffer_size (connptr->cbuffer) < MAXBUFFSIZE) + FD_SET (connptr->client_fd, &rset); + + ret = select (maxfd, &rset, &wset, NULL, &tv); + + if (ret == 0) + { + tdiff = difftime (time (NULL), last_access); + if (tdiff > config.idletimeout) + { + log_message (LOG_INFO, + "Idle Timeout (after select) as %g > %u.", + tdiff, config.idletimeout); + return; + } + else + { + continue; + } + } + else if (ret < 0) + { + log_message (LOG_ERR, + "relay_connection: select() error \"%s\". Closing connection (client_fd:%d, server_fd:%d)", + strerror (errno), connptr->client_fd, + connptr->server_fd); + return; + } + else + { + /* + * All right, something was actually selected so mark it. + */ + last_access = time (NULL); + } + + if (FD_ISSET (connptr->server_fd, &rset)) + { + bytes_received = read_buffer (connptr->server_fd, connptr->sbuffer); + if (bytes_received < 0) + break; + + connptr->content_length.server -= bytes_received; + if (connptr->content_length.server == 0) + break; + } + if (FD_ISSET (connptr->client_fd, &rset) + && read_buffer (connptr->client_fd, connptr->cbuffer) < 0) + { + break; + } + if (FD_ISSET (connptr->server_fd, &wset) + && write_buffer (connptr->server_fd, connptr->cbuffer) < 0) + { + break; + } + if (FD_ISSET (connptr->client_fd, &wset) + && write_buffer (connptr->client_fd, connptr->sbuffer) < 0) + { + break; + } + } + + /* + * Here the server has closed the connection... write the + * remainder to the client and then exit. + */ + socket_blocking (connptr->client_fd); + while (buffer_size (connptr->sbuffer) > 0) + { + if (write_buffer (connptr->client_fd, connptr->sbuffer) < 0) + break; + } + shutdown (connptr->client_fd, SHUT_WR); + + /* + * Try to send any remaining data to the server if we can. + */ + socket_blocking (connptr->server_fd); + while (buffer_size (connptr->cbuffer) > 0) + { + if (write_buffer (connptr->server_fd, connptr->cbuffer) < 0) + break; + } + + return; } /* * Establish a connection to the upstream proxy server. */ static int -connect_to_upstream(struct conn_s *connptr, struct request_s *request) +connect_to_upstream (struct conn_s *connptr, struct request_s *request) { #ifndef UPSTREAM_SUPPORT - /* - * This function does nothing if upstream support was not compiled - * into tinyproxy. - */ - return -1; + /* + * This function does nothing if upstream support was not compiled + * into tinyproxy. + */ + return -1; #else - char *combined_string; - int len; - - struct upstream *cur_upstream = connptr->upstream_proxy; - - if (!cur_upstream) { - log_message(LOG_WARNING, - "No upstream proxy defined for %s.", request->host); - indicate_http_error(connptr, 404, - "Unable to connect to upstream proxy."); - return -1; - } - - connptr->server_fd = - opensock(cur_upstream->host, cur_upstream->port, - connptr->server_ip_addr); - - if (connptr->server_fd < 0) { - log_message(LOG_WARNING, - "Could not connect to upstream proxy."); - indicate_http_error(connptr, 404, - "Unable to connect to upstream proxy", - "detail", - "A network error occurred while trying to connect to the upstream web proxy.", - NULL); - return -1; - } - - log_message(LOG_CONN, - "Established connection to upstream proxy \"%s\" using file descriptor %d.", - cur_upstream->host, connptr->server_fd); - - /* - * We need to re-write the "path" part of the request so that we - * can reuse the establish_http_connection() function. It expects a - * method and path. - */ - if (connptr->connect_method) { - len = strlen(request->host) + 7; - - combined_string = safemalloc(len); - if (!combined_string) { - return -1; - } - - snprintf(combined_string, len, "%s:%d", request->host, - request->port); - } else { - len = strlen(request->host) + strlen(request->path) + 14; - combined_string = safemalloc(len); - if (!combined_string) { - return -1; - } - - snprintf(combined_string, len, "http://%s:%d%s", request->host, - request->port, request->path); - } - - if (request->path) - safefree(request->path); - request->path = combined_string; - - return establish_http_connection(connptr, request); + char *combined_string; + int len; + + struct upstream *cur_upstream = connptr->upstream_proxy; + + if (!cur_upstream) + { + log_message (LOG_WARNING, + "No upstream proxy defined for %s.", request->host); + indicate_http_error (connptr, 404, + "Unable to connect to upstream proxy."); + return -1; + } + + connptr->server_fd = + opensock (cur_upstream->host, cur_upstream->port, + connptr->server_ip_addr); + + if (connptr->server_fd < 0) + { + log_message (LOG_WARNING, "Could not connect to upstream proxy."); + indicate_http_error (connptr, 404, + "Unable to connect to upstream proxy", + "detail", + "A network error occurred while trying to connect to the upstream web proxy.", + NULL); + return -1; + } + + log_message (LOG_CONN, + "Established connection to upstream proxy \"%s\" using file descriptor %d.", + cur_upstream->host, connptr->server_fd); + + /* + * We need to re-write the "path" part of the request so that we + * can reuse the establish_http_connection() function. It expects a + * method and path. + */ + if (connptr->connect_method) + { + len = strlen (request->host) + 7; + + combined_string = safemalloc (len); + if (!combined_string) + { + return -1; + } + + snprintf (combined_string, len, "%s:%d", request->host, request->port); + } + else + { + len = strlen (request->host) + strlen (request->path) + 14; + combined_string = safemalloc (len); + if (!combined_string) + { + return -1; + } + + snprintf (combined_string, len, "http://%s:%d%s", request->host, + request->port, request->path); + } + + if (request->path) + safefree (request->path); + request->path = combined_string; + + return establish_http_connection (connptr, request); #endif } @@ -1498,168 +1589,190 @@ connect_to_upstream(struct conn_s *connptr, struct request_s *request) * - rjkaes */ void -handle_connection(int fd) +handle_connection (int fd) { - struct conn_s *connptr; - struct request_s *request = NULL; - hashmap_t hashofheaders = NULL; - - char sock_ipaddr[IP_LENGTH]; - char peer_ipaddr[IP_LENGTH]; - char peer_string[HOSTNAME_LENGTH]; - - getpeer_information(fd, peer_ipaddr, peer_string); - - if (config.bindsame) - getsock_ip(fd, sock_ipaddr); - - log_message(LOG_CONN, config.bindsame ? - "Connect (file descriptor %d): %s [%s] at [%s]" : - "Connect (file descriptor %d): %s [%s]", - fd, peer_string, peer_ipaddr, sock_ipaddr); - - connptr = initialize_conn(fd, peer_ipaddr, peer_string, - config.bindsame ? sock_ipaddr : 0); - if (!connptr) { - close(fd); - return; - } - - if (check_acl(fd, peer_ipaddr, peer_string) <= 0) { - update_stats(STAT_DENIED); - indicate_http_error(connptr, 403, "Access denied", - "detail", - "The administrator of this proxy has not configured it to service requests from your host.", - NULL); - send_http_error_message(connptr); - destroy_conn(connptr); - return; - } - - if (read_request_line(connptr) < 0) { - update_stats(STAT_BADCONN); - indicate_http_error(connptr, 408, "Timeout", - "detail", - "Server timeout waiting for the HTTP request from the client.", - NULL); - send_http_error_message(connptr); - destroy_conn(connptr); - return; - } - - /* - * The "hashofheaders" store the client's headers. - */ - if (!(hashofheaders = hashmap_create(HEADER_BUCKETS))) { - update_stats(STAT_BADCONN); - indicate_http_error(connptr, 503, "Internal error", - "detail", - "An internal server error occurred while processing your request. Please contact the administrator.", - NULL); - send_http_error_message(connptr); - destroy_conn(connptr); - return; - } - - /* - * Get all the headers from the client in a big hash. - */ - if (get_all_headers(connptr->client_fd, hashofheaders) < 0) { - log_message(LOG_WARNING, - "Could not retrieve all the headers from the client"); - hashmap_delete(hashofheaders); - update_stats(STAT_BADCONN); - destroy_conn(connptr); - return; - } - - request = process_request(connptr, hashofheaders); - if (!request) { - if (!connptr->error_variables && !connptr->show_stats) { - update_stats(STAT_BADCONN); - destroy_conn(connptr); - hashmap_delete(hashofheaders); - return; - } - goto send_error; - } - - connptr->upstream_proxy = UPSTREAM_HOST(request->host); - if (connptr->upstream_proxy != NULL) { - if (connect_to_upstream(connptr, request) < 0) { - goto send_error; - } - } else { - connptr->server_fd = opensock(request->host, request->port, - connptr->server_ip_addr); - if (connptr->server_fd < 0) { - indicate_http_error(connptr, 500, "Unable to connect", - "detail", - PACKAGE - " was unable to connect to the remote web server.", - "error", strerror(errno), NULL); - goto send_error; - } - - log_message(LOG_CONN, - "Established connection to host \"%s\" using file descriptor %d.", - request->host, connptr->server_fd); - - if (!connptr->connect_method) - establish_http_connection(connptr, request); - } - - send_error: - free_request_struct(request); - - if (process_client_headers(connptr, hashofheaders) < 0) { - update_stats(STAT_BADCONN); - if (!connptr->error_variables) { - hashmap_delete(hashofheaders); - destroy_conn(connptr); - return; - } - } - hashmap_delete(hashofheaders); - - if (connptr->error_variables) { - send_http_error_message(connptr); - destroy_conn(connptr); - return; - } else if (connptr->show_stats) { - showstats(connptr); - destroy_conn(connptr); - return; - } - - if (!connptr->connect_method || (connptr->upstream_proxy != NULL)) { - if (process_server_headers(connptr) < 0) { - if (connptr->error_variables) - send_http_error_message(connptr); - - update_stats(STAT_BADCONN); - destroy_conn(connptr); - return; - } - } else { - if (send_ssl_response(connptr) < 0) { - log_message(LOG_ERR, - "handle_connection: Could not send SSL greeting to client."); - update_stats(STAT_BADCONN); - destroy_conn(connptr); - return; - } - } - - relay_connection(connptr); - - log_message(LOG_INFO, - "Closed connection between local client (fd:%d) and remote client (fd:%d)", - connptr->client_fd, connptr->server_fd); - - /* - * All done... close everything and go home... :) - */ - destroy_conn(connptr); - return; + struct conn_s *connptr; + struct request_s *request = NULL; + hashmap_t hashofheaders = NULL; + + char sock_ipaddr[IP_LENGTH]; + char peer_ipaddr[IP_LENGTH]; + char peer_string[HOSTNAME_LENGTH]; + + getpeer_information (fd, peer_ipaddr, peer_string); + + if (config.bindsame) + getsock_ip (fd, sock_ipaddr); + + log_message (LOG_CONN, config.bindsame ? + "Connect (file descriptor %d): %s [%s] at [%s]" : + "Connect (file descriptor %d): %s [%s]", + fd, peer_string, peer_ipaddr, sock_ipaddr); + + connptr = initialize_conn (fd, peer_ipaddr, peer_string, + config.bindsame ? sock_ipaddr : 0); + if (!connptr) + { + close (fd); + return; + } + + if (check_acl (fd, peer_ipaddr, peer_string) <= 0) + { + update_stats (STAT_DENIED); + indicate_http_error (connptr, 403, "Access denied", + "detail", + "The administrator of this proxy has not configured it to service requests from your host.", + NULL); + send_http_error_message (connptr); + destroy_conn (connptr); + return; + } + + if (read_request_line (connptr) < 0) + { + update_stats (STAT_BADCONN); + indicate_http_error (connptr, 408, "Timeout", + "detail", + "Server timeout waiting for the HTTP request from the client.", + NULL); + send_http_error_message (connptr); + destroy_conn (connptr); + return; + } + + /* + * The "hashofheaders" store the client's headers. + */ + if (!(hashofheaders = hashmap_create (HEADER_BUCKETS))) + { + update_stats (STAT_BADCONN); + indicate_http_error (connptr, 503, "Internal error", + "detail", + "An internal server error occurred while processing your request. Please contact the administrator.", + NULL); + send_http_error_message (connptr); + destroy_conn (connptr); + return; + } + + /* + * Get all the headers from the client in a big hash. + */ + if (get_all_headers (connptr->client_fd, hashofheaders) < 0) + { + log_message (LOG_WARNING, + "Could not retrieve all the headers from the client"); + hashmap_delete (hashofheaders); + update_stats (STAT_BADCONN); + destroy_conn (connptr); + return; + } + + request = process_request (connptr, hashofheaders); + if (!request) + { + if (!connptr->error_variables && !connptr->show_stats) + { + update_stats (STAT_BADCONN); + destroy_conn (connptr); + hashmap_delete (hashofheaders); + return; + } + goto send_error; + } + + connptr->upstream_proxy = UPSTREAM_HOST (request->host); + if (connptr->upstream_proxy != NULL) + { + if (connect_to_upstream (connptr, request) < 0) + { + goto send_error; + } + } + else + { + connptr->server_fd = opensock (request->host, request->port, + connptr->server_ip_addr); + if (connptr->server_fd < 0) + { + indicate_http_error (connptr, 500, "Unable to connect", + "detail", + PACKAGE + " was unable to connect to the remote web server.", + "error", strerror (errno), NULL); + goto send_error; + } + + log_message (LOG_CONN, + "Established connection to host \"%s\" using file descriptor %d.", + request->host, connptr->server_fd); + + if (!connptr->connect_method) + establish_http_connection (connptr, request); + } + +send_error: + free_request_struct (request); + + if (process_client_headers (connptr, hashofheaders) < 0) + { + update_stats (STAT_BADCONN); + if (!connptr->error_variables) + { + hashmap_delete (hashofheaders); + destroy_conn (connptr); + return; + } + } + hashmap_delete (hashofheaders); + + if (connptr->error_variables) + { + send_http_error_message (connptr); + destroy_conn (connptr); + return; + } + else if (connptr->show_stats) + { + showstats (connptr); + destroy_conn (connptr); + return; + } + + if (!connptr->connect_method || (connptr->upstream_proxy != NULL)) + { + if (process_server_headers (connptr) < 0) + { + if (connptr->error_variables) + send_http_error_message (connptr); + + update_stats (STAT_BADCONN); + destroy_conn (connptr); + return; + } + } + else + { + if (send_ssl_response (connptr) < 0) + { + log_message (LOG_ERR, + "handle_connection: Could not send SSL greeting to client."); + update_stats (STAT_BADCONN); + destroy_conn (connptr); + return; + } + } + + relay_connection (connptr); + + log_message (LOG_INFO, + "Closed connection between local client (fd:%d) and remote client (fd:%d)", + connptr->client_fd, connptr->server_fd); + + /* + * All done... close everything and go home... :) + */ + destroy_conn (connptr); + return; } @@ -34,18 +34,19 @@ /* * This structure holds the information pulled from a URL request. */ -struct request_s { - char *method; - char *protocol; +struct request_s +{ + char *method; + char *protocol; - char *host; - uint16_t port; + char *host; + uint16_t port; - char *path; + char *path; }; -extern void handle_connection(int fd); -extern void add_connect_port_allowed(int port); -extern void upstream_add(const char *host, int port, const char *domain); +extern void handle_connection (int fd); +extern void add_connect_port_allowed (int port); +extern void upstream_add (const char *host, int port, const char *domain); #endif diff --git a/src/reverse-proxy.c b/src/reverse-proxy.c index 9915540..2ed98b4 100644 --- a/src/reverse-proxy.c +++ b/src/reverse-proxy.c @@ -30,128 +30,132 @@ * Add entry to the reversepath list */ void -reversepath_add(const char *path, const char *url) +reversepath_add (const char *path, const char *url) { - struct reversepath *reverse; - - if (url == NULL) { - log_message(LOG_WARNING, - "Illegal reverse proxy rule: missing url"); - return; - } - - if (!strstr(url, "://")) { - log_message(LOG_WARNING, - "Skipping reverse proxy rule: '%s' is not a valid url", - url); - return; - } - - if (path && *path != '/') { - log_message(LOG_WARNING, - "Skipping reverse proxy rule: path '%s' doesn't start with a /", - path); - return; - } - - if (!(reverse = safemalloc(sizeof(struct reversepath)))) { - log_message(LOG_ERR, - "Unable to allocate memory in reversepath_add()"); - return; - } - - if (!path) - reverse->path = safestrdup("/"); - else - reverse->path = safestrdup(path); - - reverse->url = safestrdup(url); - - reverse->next = config.reversepath_list; - config.reversepath_list = reverse; - - log_message(LOG_INFO, - "Added reverse proxy rule: %s -> %s", reverse->path, - reverse->url); + struct reversepath *reverse; + + if (url == NULL) + { + log_message (LOG_WARNING, "Illegal reverse proxy rule: missing url"); + return; + } + + if (!strstr (url, "://")) + { + log_message (LOG_WARNING, + "Skipping reverse proxy rule: '%s' is not a valid url", + url); + return; + } + + if (path && *path != '/') + { + log_message (LOG_WARNING, + "Skipping reverse proxy rule: path '%s' doesn't start with a /", + path); + return; + } + + if (!(reverse = safemalloc (sizeof (struct reversepath)))) + { + log_message (LOG_ERR, "Unable to allocate memory in reversepath_add()"); + return; + } + + if (!path) + reverse->path = safestrdup ("/"); + else + reverse->path = safestrdup (path); + + reverse->url = safestrdup (url); + + reverse->next = config.reversepath_list; + config.reversepath_list = reverse; + + log_message (LOG_INFO, + "Added reverse proxy rule: %s -> %s", reverse->path, + reverse->url); } /* * Check if a request url is in the reversepath list */ struct reversepath * -reversepath_get(char *url) +reversepath_get (char *url) { - struct reversepath *reverse = config.reversepath_list; + struct reversepath *reverse = config.reversepath_list; - while (reverse) { - if (strstr(url, reverse->path) == url) - return reverse; + while (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. */ 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 *cookie = NULL; - char *cookieval; - struct reversepath *reverse; - - /* Reverse requests always start with a slash */ - if (*url == '/') { - /* First try locating the reverse mapping by request url */ - reverse = reversepath_get(url); - if (reverse) { - rewrite_url = safemalloc(strlen(url) + - strlen(reverse->url) + 1); - strcpy(rewrite_url, reverse->url); - strcat(rewrite_url, url + strlen(reverse->path)); - } else if (config.reversemagic - && hashmap_entry_by_key(hashofheaders, - "cookie", - (void **)&cookie) > 0) { - - /* No match - try the magical tracking cookie next */ - if ((cookieval = strstr(cookie, REVERSE_COOKIE "=")) - && (reverse = - reversepath_get(cookieval + - strlen(REVERSE_COOKIE) + 1))) { - - rewrite_url = safemalloc(strlen(url) + - strlen - (reverse->url) + 1); - strcpy(rewrite_url, reverse->url); - strcat(rewrite_url, url + 1); - - log_message(LOG_INFO, - "Magical tracking cookie says: %s", - reverse->path); - } - } - } - - /* Forward proxy support off and no reverse path match found */ - if (config.reverseonly && !rewrite_url) { - log_message(LOG_ERR, "Bad request"); - indicate_http_error(connptr, 400, "Bad Request", - "detail", - "Request has an invalid URL", "url", - url, NULL); - return NULL; - } - - log_message(LOG_CONN, "Rewriting URL: %s -> %s", url, rewrite_url); - - /* Store reverse path so that the magical tracking cookie can be set */ - if (config.reversemagic) - connptr->reversepath = safestrdup(reverse->path); - - return rewrite_url; + char *rewrite_url = NULL; + char *cookie = NULL; + char *cookieval; + struct reversepath *reverse; + + /* Reverse requests always start with a slash */ + if (*url == '/') + { + /* First try locating the reverse mapping by request url */ + reverse = reversepath_get (url); + if (reverse) + { + rewrite_url = safemalloc (strlen (url) + strlen (reverse->url) + 1); + strcpy (rewrite_url, reverse->url); + strcat (rewrite_url, url + strlen (reverse->path)); + } + else if (config.reversemagic + && hashmap_entry_by_key (hashofheaders, + "cookie", (void **) &cookie) > 0) + { + + /* No match - try the magical tracking cookie next */ + if ((cookieval = strstr (cookie, REVERSE_COOKIE "=")) + && (reverse = + reversepath_get (cookieval + strlen (REVERSE_COOKIE) + 1))) + { + + rewrite_url = safemalloc (strlen (url) + + strlen (reverse->url) + 1); + strcpy (rewrite_url, reverse->url); + strcat (rewrite_url, url + 1); + + log_message (LOG_INFO, + "Magical tracking cookie says: %s", reverse->path); + } + } + } + + /* Forward proxy support off and no reverse path match found */ + if (config.reverseonly && !rewrite_url) + { + log_message (LOG_ERR, "Bad request"); + indicate_http_error (connptr, 400, "Bad Request", + "detail", + "Request has an invalid URL", "url", url, NULL); + return NULL; + } + + log_message (LOG_CONN, "Rewriting URL: %s -> %s", url, rewrite_url); + + /* Store reverse path so that the magical tracking cookie can be set */ + if (config.reversemagic) + connptr->reversepath = safestrdup (reverse->path); + + return rewrite_url; } diff --git a/src/reverse-proxy.h b/src/reverse-proxy.h index 2ad8522..2bb8a16 100644 --- a/src/reverse-proxy.h +++ b/src/reverse-proxy.h @@ -23,17 +23,18 @@ #include "conns.h" -struct reversepath { - struct reversepath *next; - char *path; - char *url; +struct reversepath +{ + struct reversepath *next; + char *path; + char *url; }; #define REVERSE_COOKIE "yummy_magical_cookie" -extern void reversepath_add(const char *path, const char *url); -extern struct reversepath *reversepath_get(char *url); -extern char *reverse_rewrite_url(struct conn_s *connptr, - hashmap_t hashofheaders, char *url); +extern void reversepath_add (const char *path, const char *url); +extern struct reversepath *reversepath_get (char *url); +extern char *reverse_rewrite_url (struct conn_s *connptr, + hashmap_t hashofheaders, char *url); #endif @@ -39,34 +39,36 @@ * to indicate an error. */ 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(addr != NULL && strlen(addr) != 0); + assert (sockfd >= 0); + assert (addr != NULL && strlen (addr) != 0); - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; + memset (&hints, 0, sizeof (struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; - /* The local port it not important */ - if (getaddrinfo(addr, NULL, &hints, &res) != 0) - return -1; + /* The local port it not important */ + if (getaddrinfo (addr, NULL, &hints, &res) != 0) + return -1; - ressave = res; + ressave = res; - /* Loop through the addresses and try to bind to each */ - do { - if (bind(sockfd, res->ai_addr, res->ai_addrlen) == 0) - break; /* success */ - } while ((res = res->ai_next) != NULL); + /* Loop through the addresses and try to bind to each */ + do + { + if (bind (sockfd, res->ai_addr, res->ai_addrlen) == 0) + break; /* success */ + } + while ((res = res->ai_next) != NULL); - freeaddrinfo(ressave); - if (res == NULL) /* was not able to bind to any address */ - return -1; + freeaddrinfo (ressave); + if (res == NULL) /* was not able to bind to any address */ + 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.) */ int -opensock(const char *host, int port, const char *bind_to) +opensock (const char *host, int port, const char *bind_to) { - int sockfd, n; - struct addrinfo hints, *res, *ressave; - char portstr[6]; - - assert(host != NULL); - assert(port > 0); - - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - - snprintf(portstr, sizeof(portstr), "%d", port); - - n = getaddrinfo(host, portstr, &hints, &res); - if (n != 0) { - log_message(LOG_ERR, "opensock: Could not retrieve info for %s", - host); - return -1; - } - - ressave = res; - do { - sockfd = - socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (sockfd < 0) - continue; /* ignore this one */ - - /* Bind to the specified address */ - if (bind_to) { - if (bind_socket(sockfd, bind_to) < 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) - break; /* success */ - - close(sockfd); - } while ((res = res->ai_next) != NULL); - - freeaddrinfo(ressave); - if (res == NULL) { - log_message(LOG_ERR, - "opensock: Could not establish a connection to %s", - host); - return -1; - } - - return sockfd; + int sockfd, n; + struct addrinfo hints, *res, *ressave; + char portstr[6]; + + assert (host != NULL); + assert (port > 0); + + memset (&hints, 0, sizeof (struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + snprintf (portstr, sizeof (portstr), "%d", port); + + n = getaddrinfo (host, portstr, &hints, &res); + if (n != 0) + { + log_message (LOG_ERR, "opensock: Could not retrieve info for %s", host); + return -1; + } + + ressave = res; + do + { + sockfd = socket (res->ai_family, res->ai_socktype, res->ai_protocol); + if (sockfd < 0) + continue; /* ignore this one */ + + /* Bind to the specified address */ + if (bind_to) + { + if (bind_socket (sockfd, bind_to) < 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) + break; /* success */ + + close (sockfd); + } + while ((res = res->ai_next) != NULL); + + freeaddrinfo (ressave); + if (res == NULL) + { + log_message (LOG_ERR, + "opensock: Could not establish a connection to %s", host); + return -1; + } + + return sockfd; } /* * Set the socket to non blocking -rjkaes */ 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); - return fcntl(sock, F_SETFL, flags | O_NONBLOCK); + flags = fcntl (sock, F_GETFL, 0); + return fcntl (sock, F_SETFL, flags | O_NONBLOCK); } /* * Set the socket to blocking -rjkaes */ 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); - return fcntl(sock, F_SETFL, flags & ~O_NONBLOCK); + flags = fcntl (sock, F_GETFL, 0); + return fcntl (sock, F_SETFL, flags & ~O_NONBLOCK); } /* @@ -169,95 +177,101 @@ socket_blocking(int sock) * - rjkaes */ int -listen_sock(uint16_t port, socklen_t * addrlen) +listen_sock (uint16_t port, socklen_t * addrlen) { - int listenfd; - const int on = 1; - struct sockaddr_in addr; - - assert(port > 0); - assert(addrlen != NULL); - - listenfd = socket(AF_INET, SOCK_STREAM, 0); - setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - - if (config.ipAddr) { - addr.sin_addr.s_addr = inet_addr(config.ipAddr); - } else { - addr.sin_addr.s_addr = inet_addr("0.0.0.0"); - } - - if (bind(listenfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - log_message(LOG_ERR, - "Unable to bind listening socket because of %s", - strerror(errno)); - return -1; - } - - if (listen(listenfd, MAXLISTEN) < 0) { - log_message(LOG_ERR, - "Unable to start listening socket because of %s", - strerror(errno)); - return -1; - } - - *addrlen = sizeof(addr); - - return listenfd; + int listenfd; + const int on = 1; + struct sockaddr_in addr; + + assert (port > 0); + assert (addrlen != NULL); + + listenfd = socket (AF_INET, SOCK_STREAM, 0); + setsockopt (listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)); + + memset (&addr, 0, sizeof (addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons (port); + + if (config.ipAddr) + { + addr.sin_addr.s_addr = inet_addr (config.ipAddr); + } + else + { + addr.sin_addr.s_addr = inet_addr ("0.0.0.0"); + } + + if (bind (listenfd, (struct sockaddr *) &addr, sizeof (addr)) < 0) + { + log_message (LOG_ERR, + "Unable to bind listening socket because of %s", + strerror (errno)); + return -1; + } + + if (listen (listenfd, MAXLISTEN) < 0) + { + log_message (LOG_ERR, + "Unable to start listening socket because of %s", + strerror (errno)); + return -1; + } + + *addrlen = sizeof (addr); + + return listenfd; } /* * Takes a socket descriptor and returns the socket's IP address. */ int -getsock_ip(int fd, char *ipaddr) +getsock_ip (int fd, char *ipaddr) { - struct sockaddr_storage name; - socklen_t namelen = sizeof(name); + struct sockaddr_storage name; + socklen_t namelen = sizeof (name); - assert(fd >= 0); + assert (fd >= 0); - if (getsockname(fd, (struct sockaddr *)&name, &namelen) != 0) { - log_message(LOG_ERR, "getsock_ip: getsockname() error: %s", - strerror(errno)); - return -1; - } + if (getsockname (fd, (struct sockaddr *) &name, &namelen) != 0) + { + log_message (LOG_ERR, "getsock_ip: getsockname() error: %s", + strerror (errno)); + return -1; + } - if (get_ip_string((struct sockaddr *)&name, ipaddr, IP_LENGTH) == NULL) - return -1; + if (get_ip_string ((struct sockaddr *) &name, ipaddr, IP_LENGTH) == NULL) + return -1; - return 0; + return 0; } /* * Return the peer's socket information. */ int -getpeer_information(int fd, char *ipaddr, char *string_addr) +getpeer_information (int fd, char *ipaddr, char *string_addr) { - struct sockaddr_storage sa; - socklen_t salen = sizeof sa; + struct sockaddr_storage sa; + socklen_t salen = sizeof sa; - assert(fd >= 0); - assert(ipaddr != NULL); - assert(string_addr != NULL); + assert (fd >= 0); + assert (ipaddr != NULL); + assert (string_addr != NULL); - /* Set the strings to default values */ - ipaddr[0] = '\0'; - strlcpy(string_addr, "[unknown]", HOSTNAME_LENGTH); + /* Set the strings to default values */ + ipaddr[0] = '\0'; + strlcpy (string_addr, "[unknown]", HOSTNAME_LENGTH); - /* Look up the IP address */ - if (getpeername(fd, (struct sockaddr *) &sa, &salen) != 0) - return -1; + /* Look up the IP address */ + if (getpeername (fd, (struct sockaddr *) &sa, &salen) != 0) + return -1; - if (get_ip_string((struct sockaddr *)&sa, ipaddr, IP_LENGTH) == NULL) - return -1; + if (get_ip_string ((struct sockaddr *) &sa, ipaddr, IP_LENGTH) == NULL) + return -1; - /* Get the full host name */ - return getnameinfo((struct sockaddr *)&sa, salen, - string_addr, HOSTNAME_LENGTH, NULL, 0, 0); + /* Get the full host name */ + return getnameinfo ((struct sockaddr *) &sa, salen, + string_addr, HOSTNAME_LENGTH, NULL, 0, 0); } @@ -28,13 +28,13 @@ #define MAXLINE (1024 * 4) -extern int opensock(const char *host, int port, const char *bind_to); -extern int listen_sock(uint16_t port, socklen_t * addrlen); +extern int opensock (const char *host, int port, const char *bind_to); +extern int listen_sock (uint16_t port, socklen_t * addrlen); -extern int socket_nonblocking(int sock); -extern int socket_blocking(int sock); +extern int socket_nonblocking (int sock); +extern int socket_blocking (int sock); -extern int getsock_ip(int fd, char *ipaddr); -extern int getpeer_information(int fd, char *ipaddr, char *string_addr); +extern int getsock_ip (int fd, char *ipaddr); +extern int getpeer_information (int fd, char *ipaddr, char *string_addr); #endif diff --git a/src/stats.c b/src/stats.c index 1b958ce..25a053d 100644 --- a/src/stats.c +++ b/src/stats.c @@ -33,12 +33,13 @@ #include "stats.h" #include "utils.h" -struct stat_s { - unsigned long int num_reqs; - unsigned long int num_badcons; - unsigned long int num_open; - unsigned long int num_refused; - unsigned long int num_denied; +struct stat_s +{ + unsigned long int num_reqs; + unsigned long int num_badcons; + unsigned long int num_open; + unsigned long int num_refused; + unsigned long int num_denied; }; static struct stat_s *stats; @@ -47,83 +48,82 @@ static struct stat_s *stats; * Initialize the statistics information to zero. */ void -init_stats(void) +init_stats (void) { - stats = malloc_shared_memory(sizeof(struct stat_s)); - if (stats == MAP_FAILED) - return; + stats = malloc_shared_memory (sizeof (struct stat_s)); + if (stats == MAP_FAILED) + return; - memset(stats, 0, sizeof(struct stat_s)); + memset (stats, 0, sizeof (struct stat_s)); } /* * Display the statics of the tinyproxy server. */ int -showstats(struct conn_s *connptr) +showstats (struct conn_s *connptr) { - static char *msg = - "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" - "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n" - "<html>\n" - "<head><title>%s version %s run-time statistics</title></head>\n" - "<body>\n" - "<h1>%s version %s run-time statistics</h1>\n" - "<p>\n" - "Number of open connections: %lu<br />\n" - "Number of requests: %lu<br />\n" - "Number of bad connections: %lu<br />\n" - "Number of denied connections: %lu<br />\n" - "Number of refused connections due to high load: %lu\n" - "</p>\n" - "<hr />\n" - "<p><em>Generated by %s version %s.</em></p>\n" - "</body>\n" - "</html>\n"; - - char *message_buffer; - char opens[16], reqs[16], badconns[16], denied[16], refused[16]; - FILE *statfile; - - snprintf(opens, sizeof(opens), "%lu", stats->num_open); - snprintf(reqs, sizeof(reqs), "%lu", stats->num_reqs); - snprintf(badconns, sizeof(badconns), "%lu", stats->num_badcons); - snprintf(denied, sizeof(denied), "%lu", stats->num_denied); - snprintf(refused, sizeof(refused), "%lu", stats->num_refused); - - if (!config.statpage || (!(statfile = fopen(config.statpage, "r")))) { - message_buffer = safemalloc(MAXBUFFSIZE); - if (!message_buffer) - return -1; - - snprintf(message_buffer, MAXBUFFSIZE, msg, - PACKAGE, VERSION, PACKAGE, VERSION, - stats->num_open, - stats->num_reqs, - stats->num_badcons, stats->num_denied, - stats->num_refused, - PACKAGE, VERSION); - - if (send_http_message(connptr, 200, "OK", message_buffer) < 0) { - safefree(message_buffer); - return -1; - } - - safefree(message_buffer); - return 0; - } - - add_error_variable(connptr, "opens", opens); - add_error_variable(connptr, "reqs", reqs); - add_error_variable(connptr, "badconns", badconns); - add_error_variable(connptr, "deniedconns", denied); - add_error_variable(connptr, "refusedconns", refused); - add_standard_vars(connptr); - send_http_headers(connptr, 200, "Statistic requested"); - send_html_file(statfile, connptr); - fclose(statfile); - - return 0; + static char *msg = + "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n" + "<html>\n" + "<head><title>%s version %s run-time statistics</title></head>\n" + "<body>\n" + "<h1>%s version %s run-time statistics</h1>\n" + "<p>\n" + "Number of open connections: %lu<br />\n" + "Number of requests: %lu<br />\n" + "Number of bad connections: %lu<br />\n" + "Number of denied connections: %lu<br />\n" + "Number of refused connections due to high load: %lu\n" + "</p>\n" + "<hr />\n" + "<p><em>Generated by %s version %s.</em></p>\n" "</body>\n" "</html>\n"; + + char *message_buffer; + char opens[16], reqs[16], badconns[16], denied[16], refused[16]; + FILE *statfile; + + snprintf (opens, sizeof (opens), "%lu", stats->num_open); + snprintf (reqs, sizeof (reqs), "%lu", stats->num_reqs); + snprintf (badconns, sizeof (badconns), "%lu", stats->num_badcons); + snprintf (denied, sizeof (denied), "%lu", stats->num_denied); + snprintf (refused, sizeof (refused), "%lu", stats->num_refused); + + if (!config.statpage || (!(statfile = fopen (config.statpage, "r")))) + { + message_buffer = safemalloc (MAXBUFFSIZE); + if (!message_buffer) + return -1; + + snprintf (message_buffer, MAXBUFFSIZE, msg, + PACKAGE, VERSION, PACKAGE, VERSION, + stats->num_open, + stats->num_reqs, + stats->num_badcons, stats->num_denied, + stats->num_refused, PACKAGE, VERSION); + + if (send_http_message (connptr, 200, "OK", message_buffer) < 0) + { + safefree (message_buffer); + return -1; + } + + safefree (message_buffer); + return 0; + } + + add_error_variable (connptr, "opens", opens); + add_error_variable (connptr, "reqs", reqs); + add_error_variable (connptr, "badconns", badconns); + add_error_variable (connptr, "deniedconns", denied); + add_error_variable (connptr, "refusedconns", refused); + add_standard_vars (connptr); + send_http_headers (connptr, 200, "Statistic requested"); + send_html_file (statfile, connptr); + fclose (statfile); + + return 0; } /* @@ -131,28 +131,29 @@ showstats(struct conn_s *connptr) * stats.h */ int -update_stats(status_t update_level) +update_stats (status_t update_level) { - switch (update_level) { - case STAT_BADCONN: - ++stats->num_badcons; - break; - case STAT_OPEN: - ++stats->num_open; - ++stats->num_reqs; - break; - case STAT_CLOSE: - --stats->num_open; - break; - case STAT_REFUSE: - ++stats->num_refused; - break; - case STAT_DENIED: - ++stats->num_denied; - break; - default: - return -1; - } - - return 0; + switch (update_level) + { + case STAT_BADCONN: + ++stats->num_badcons; + break; + case STAT_OPEN: + ++stats->num_open; + ++stats->num_reqs; + break; + case STAT_CLOSE: + --stats->num_open; + break; + case STAT_REFUSE: + ++stats->num_refused; + break; + case STAT_DENIED: + ++stats->num_denied; + break; + default: + return -1; + } + + return 0; } diff --git a/src/stats.h b/src/stats.h index b7a8218..a75d92e 100644 --- a/src/stats.h +++ b/src/stats.h @@ -26,19 +26,20 @@ /* * Various logable statistics */ -typedef enum { - STAT_BADCONN, /* bad connection, for unknown reason */ - STAT_OPEN, /* connection opened */ - STAT_CLOSE, /* connection closed */ - STAT_REFUSE, /* connection refused (to outside world) */ - STAT_DENIED /* connection denied to tinyproxy itself */ +typedef enum +{ + STAT_BADCONN, /* bad connection, for unknown reason */ + STAT_OPEN, /* connection opened */ + STAT_CLOSE, /* connection closed */ + STAT_REFUSE, /* connection refused (to outside world) */ + STAT_DENIED /* connection denied to tinyproxy itself */ } status_t; /* * Public API to the statistics for tinyproxy */ -extern void init_stats(void); -extern int showstats(struct conn_s *connptr); -extern int update_stats(status_t update_level); +extern void init_stats (void); +extern int showstats (struct conn_s *connptr); +extern int update_stats (status_t update_level); #endif @@ -33,18 +33,18 @@ * destination buffer. */ 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 ret = len; + size_t len = strlen (src); + size_t ret = len; - if (len >= size) - len = size - 1; + if (len >= size) + len = size - 1; - memcpy(dst, src, len); - dst[len] = '\0'; + memcpy (dst, src, len); + dst[len] = '\0'; - return ret; + return ret; } #endif @@ -56,20 +56,21 @@ strlcpy(char *dst, const char *src, size_t size) * length. */ 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 len2 = strlen(src); - size_t ret = len1 + len2; - - if (len1 + len2 >= size) - len2 = size - len1 - 1; - if (len2 > 0) { - memcpy(dst + len1, src, len2); - dst[len1 + len2] = '\0'; - } - - return ret; + size_t len1 = strlen (dst); + size_t len2 = strlen (src); + size_t ret = len1 + len2; + + if (len1 + len2 >= size) + len2 = size - len1 - 1; + if (len2 > 0) + { + memcpy (dst + len1, src, len2); + dst[len1 + len2] = '\0'; + } + + return ret; } #endif @@ -83,30 +84,31 @@ strlcat(char *dst, const char *src, size_t size) * negative return value indicates an error. */ ssize_t -chomp(char *buffer, size_t length) +chomp (char *buffer, size_t length) { - size_t chars; + size_t chars; - assert(buffer != NULL); - assert(length > 0); + assert (buffer != NULL); + assert (length > 0); - /* Make sure the arguments are valid */ - if (buffer == NULL) - return -EFAULT; - if (length < 1) - return -ERANGE; + /* Make sure the arguments are valid */ + if (buffer == NULL) + return -EFAULT; + if (length < 1) + return -ERANGE; - chars = 0; + chars = 0; - --length; - while (buffer[length] == '\r' || buffer[length] == '\n') { - buffer[length] = '\0'; - chars++; + --length; + while (buffer[length] == '\r' || buffer[length] == '\n') + { + buffer[length] = '\0'; + chars++; - /* Stop once we get to zero to prevent wrap-around */ - if (length-- == 0) - break; - } + /* Stop once we get to zero to prevent wrap-around */ + if (length-- == 0) + break; + } - return chars; + return chars; } @@ -22,13 +22,13 @@ #define TINYPROXY_TEXT_H #ifndef HAVE_STRLCAT -extern size_t strlcat(char *dst, const char *src, size_t size); -#endif /* HAVE_STRLCAT */ +extern size_t strlcat (char *dst, const char *src, size_t size); +#endif /* HAVE_STRLCAT */ #ifndef HAVE_STRLCPY -extern size_t strlcpy(char *dst, const char *src, size_t size); -#endif /* HAVE_STRLCPY */ +extern size_t strlcpy (char *dst, const char *src, size_t size); +#endif /* HAVE_STRLCPY */ -extern ssize_t chomp(char *buffer, size_t length); +extern ssize_t chomp (char *buffer, size_t length); #endif diff --git a/src/tinyproxy.c b/src/tinyproxy.c index 03ca9b5..6708743 100644 --- a/src/tinyproxy.c +++ b/src/tinyproxy.c @@ -41,60 +41,61 @@ #include "stats.h" #include "utils.h" -RETSIGTYPE takesig(int sig); +RETSIGTYPE takesig (int sig); /* * Global Structures */ struct config_s config; float load = 0.00; -unsigned int received_sighup = FALSE; /* boolean */ -unsigned int processed_config_file = FALSE; /* boolean */ +unsigned int received_sighup = FALSE; /* boolean */ +unsigned int processed_config_file = FALSE; /* boolean */ /* * Handle a signal */ RETSIGTYPE -takesig(int sig) +takesig (int sig) { - pid_t pid; - int status; + pid_t pid; + int status; - switch (sig) { - case SIGHUP: - received_sighup = TRUE; - break; + switch (sig) + { + case SIGHUP: + received_sighup = TRUE; + break; - case SIGTERM: - config.quit = TRUE; - break; + case SIGTERM: + config.quit = TRUE; + break; - case SIGCHLD: - while ((pid = waitpid(-1, &status, WNOHANG)) > 0) ; - break; - } + case SIGCHLD: + while ((pid = waitpid (-1, &status, WNOHANG)) > 0); + break; + } - return; + return; } /* * Display the version information for the user. */ 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. */ static void -display_license(void) +display_license (void) { - display_version(); + display_version (); - printf("\ + printf ("\ Copyright 1998 Steven Young (sdyoung@well.com)\n\ Copyright 1998-2002 Robert James Kaes (rjkaes@users.sourceforge.net)\n\ Copyright 1999 George Talusan (gstalusan@uwaterloo.ca)\n\ @@ -119,10 +120,10 @@ display_license(void) * Display usage to the user. */ static void -display_usage(void) +display_usage (void) { - printf("Usage: %s [options]\n", PACKAGE); - printf("\ + printf ("Usage: %s [options]\n", PACKAGE); + printf ("\ Options:\n\ -d Operate in DEBUG mode.\n\ -c FILE Use an alternate configuration file.\n\ @@ -130,319 +131,344 @@ Options:\n\ -l Display the license.\n\ -v Display the version number.\n"); - /* Display the modes compiled into tinyproxy */ - printf("\nFeatures compiled in:\n"); + /* Display the modes compiled into tinyproxy */ + printf ("\nFeatures compiled in:\n"); #ifdef XTINYPROXY_ENABLE - printf(" XTinyproxy header\n"); -#endif /* XTINYPROXY */ + printf (" XTinyproxy header\n"); +#endif /* XTINYPROXY */ #ifdef FILTER_ENABLE - printf(" Filtering\n"); -#endif /* FILTER_ENABLE */ + printf (" Filtering\n"); +#endif /* FILTER_ENABLE */ #ifndef NDEBUG - printf(" Debugging code\n"); -#endif /* NDEBUG */ + printf (" Debugging code\n"); +#endif /* NDEBUG */ #ifdef TRANSPARENT_PROXY - printf(" Transparent proxy support\n"); -#endif /* TRANSPARENT_PROXY */ + printf (" Transparent proxy support\n"); +#endif /* TRANSPARENT_PROXY */ #ifdef REVERSE_SUPPORT - printf(" Reverse proxy support\n"); -#endif /* REVERSE_SUPPORT */ + printf (" Reverse proxy support\n"); +#endif /* REVERSE_SUPPORT */ } static int get_id (char *str) { - char *tstr; + char *tstr; - if (str == NULL) - return -1; + if (str == NULL) + return -1; - tstr = str; - while (*tstr != 0) { - if (!isdigit(*tstr)) - return -1; - tstr++; - } + tstr = str; + while (*tstr != 0) + { + if (!isdigit (*tstr)) + return -1; + tstr++; + } - return atoi(str); + return atoi (str); } int -main(int argc, char **argv) +main (int argc, char **argv) { - int optch; - unsigned int godaemon = TRUE; /* boolean */ - struct passwd *thisuser = NULL; - struct group *thisgroup = NULL; - FILE *config_file; - - /* Only allow u+rw bits. This may be required for some versions - * of glibc so that mkstemp() doesn't make us vulnerable. - */ - umask(0177); - - /* Default configuration file location */ - config.config_file = DEFAULT_CONF_FILE; - - /* - * Process the various options - */ - while ((optch = getopt(argc, argv, "c:vldh")) != EOF) { - switch (optch) { - case 'v': - display_version(); - exit(EX_OK); - case 'l': - display_license(); - exit(EX_OK); - case 'd': - godaemon = FALSE; - break; - case 'c': - config.config_file = safestrdup(optarg); - if (!config.config_file) { - fprintf(stderr, - "%s: Could not allocate memory.\n", - argv[0]); - exit(EX_SOFTWARE); - } - break; - case 'h': - default: - display_usage(); - exit(EX_OK); - } - } - - log_message(LOG_INFO, "Initializing " PACKAGE " ..."); - - /* - * Make sure the HTML error pages array is NULL to begin with. - * (FIXME: Should have a better API for all this) - */ - config.errorpages = NULL; - - /* - * Read in the settings from the config file. - */ - config_file = fopen(config.config_file, "r"); - if (!config_file) { - fprintf(stderr, - "%s: Could not open configuration file \"%s\".\n", - argv[0], config.config_file); - exit(EX_SOFTWARE); - } - if (config_compile() || config_parse(&config, config_file)) { - fprintf(stderr, - "Unable to parse configuration file. Not starting.\n"); - exit(EX_SOFTWARE); - } - fclose(config_file); - - /* - * Write to a user supplied log file if it's defined. This - * will override using the syslog even if syslog is defined. - */ - if (config.logf_name) { - if (open_log_file(config.logf_name) < 0) { - fprintf(stderr, - "%s: Could not create log file.\n", argv[0]); - exit(EX_SOFTWARE); - } - config.syslog = FALSE; /* disable syslog */ - } else if (config.syslog) { - if (godaemon == TRUE) - openlog("tinyproxy", LOG_PID, LOG_DAEMON); - else - openlog("tinyproxy", LOG_PID, LOG_USER); - } else { - fprintf(stderr, - "%s: Either define a logfile or enable syslog logging\n", - argv[0]); - exit(EX_SOFTWARE); - } - - processed_config_file = TRUE; - send_stored_logs(); - - /* - * Set the default values if they were not set in the config file. - */ - if (config.port == 0) { - fprintf(stderr, - "%s: You MUST set a Port in the configuration file.\n", - argv[0]); - exit(EX_SOFTWARE); - } - if (!config.stathost) { - log_message(LOG_INFO, "Setting stathost to \"%s\".", - DEFAULT_STATHOST); - config.stathost = DEFAULT_STATHOST; - } - if (!config.user) { - log_message(LOG_WARNING, - "You SHOULD set a UserName in the configuration file. Using current user instead."); - } - if (config.idletimeout == 0) { - 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(); - - /* - * If ANONYMOUS is turned on, make sure that Content-Length is - * 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 - * hand in hand with Content-Length. - * - rjkaes - */ - if (is_anonymous_enabled()) { - anonymous_insert("Content-Length"); - anonymous_insert("Content-Type"); - } - - if (godaemon == TRUE) - makedaemon(); - - if (config.pidpath) { - if (pidfile_create(config.pidpath) < 0) { - fprintf(stderr, "%s: Could not create PID file.\n", - argv[0]); - exit(EX_OSERR); - } - } - - if (set_signal_handler(SIGPIPE, SIG_IGN) == SIG_ERR) { - fprintf(stderr, "%s: Could not set the \"SIGPIPE\" signal.\n", - argv[0]); - exit(EX_OSERR); - } + int optch; + unsigned int godaemon = TRUE; /* boolean */ + struct passwd *thisuser = NULL; + struct group *thisgroup = NULL; + FILE *config_file; + + /* Only allow u+rw bits. This may be required for some versions + * of glibc so that mkstemp() doesn't make us vulnerable. + */ + umask (0177); + + /* Default configuration file location */ + config.config_file = DEFAULT_CONF_FILE; + + /* + * Process the various options + */ + while ((optch = getopt (argc, argv, "c:vldh")) != EOF) + { + switch (optch) + { + case 'v': + display_version (); + exit (EX_OK); + case 'l': + display_license (); + exit (EX_OK); + case 'd': + godaemon = FALSE; + break; + case 'c': + config.config_file = safestrdup (optarg); + if (!config.config_file) + { + fprintf (stderr, "%s: Could not allocate memory.\n", argv[0]); + exit (EX_SOFTWARE); + } + break; + case 'h': + default: + display_usage (); + exit (EX_OK); + } + } + + log_message (LOG_INFO, "Initializing " PACKAGE " ..."); + + /* + * Make sure the HTML error pages array is NULL to begin with. + * (FIXME: Should have a better API for all this) + */ + config.errorpages = NULL; + + /* + * Read in the settings from the config file. + */ + config_file = fopen (config.config_file, "r"); + if (!config_file) + { + fprintf (stderr, + "%s: Could not open configuration file \"%s\".\n", + argv[0], config.config_file); + exit (EX_SOFTWARE); + } + if (config_compile () || config_parse (&config, config_file)) + { + fprintf (stderr, + "Unable to parse configuration file. Not starting.\n"); + exit (EX_SOFTWARE); + } + fclose (config_file); + + /* + * Write to a user supplied log file if it's defined. This + * will override using the syslog even if syslog is defined. + */ + if (config.logf_name) + { + if (open_log_file (config.logf_name) < 0) + { + fprintf (stderr, "%s: Could not create log file.\n", argv[0]); + exit (EX_SOFTWARE); + } + config.syslog = FALSE; /* disable syslog */ + } + else if (config.syslog) + { + if (godaemon == TRUE) + openlog ("tinyproxy", LOG_PID, LOG_DAEMON); + else + openlog ("tinyproxy", LOG_PID, LOG_USER); + } + else + { + fprintf (stderr, + "%s: Either define a logfile or enable syslog logging\n", + argv[0]); + exit (EX_SOFTWARE); + } + + processed_config_file = TRUE; + send_stored_logs (); + + /* + * Set the default values if they were not set in the config file. + */ + if (config.port == 0) + { + fprintf (stderr, + "%s: You MUST set a Port in the configuration file.\n", + argv[0]); + exit (EX_SOFTWARE); + } + if (!config.stathost) + { + log_message (LOG_INFO, "Setting stathost to \"%s\".", DEFAULT_STATHOST); + config.stathost = DEFAULT_STATHOST; + } + if (!config.user) + { + log_message (LOG_WARNING, + "You SHOULD set a UserName in the configuration file. Using current user instead."); + } + if (config.idletimeout == 0) + { + 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 (); + + /* + * If ANONYMOUS is turned on, make sure that Content-Length is + * 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 + * hand in hand with Content-Length. + * - rjkaes + */ + if (is_anonymous_enabled ()) + { + anonymous_insert ("Content-Length"); + anonymous_insert ("Content-Type"); + } + + if (godaemon == TRUE) + makedaemon (); + + if (config.pidpath) + { + if (pidfile_create (config.pidpath) < 0) + { + fprintf (stderr, "%s: Could not create PID file.\n", argv[0]); + exit (EX_OSERR); + } + } + + if (set_signal_handler (SIGPIPE, SIG_IGN) == SIG_ERR) + { + fprintf (stderr, "%s: Could not set the \"SIGPIPE\" signal.\n", + argv[0]); + exit (EX_OSERR); + } #ifdef FILTER_ENABLE - if (config.filter) - filter_init(); -#endif /* FILTER_ENABLE */ - - /* - * Start listening on the selected port. - */ - if (child_listening_sock(config.port) < 0) { - fprintf(stderr, "%s: Could not create listening socket.\n", - argv[0]); - exit(EX_OSERR); - } - - /* - * Switch to a different user. - */ - if (geteuid() == 0) { - if (config.group && strlen(config.group) > 0) { - int gid = get_id(config.group); - if (gid < 0) { - thisgroup = getgrnam(config.group); - if (!thisgroup) { - fprintf(stderr, - "%s: Unable to find " - "group \"%s\".\n", - argv[0], config.group); - exit(EX_NOUSER); - } - gid = thisgroup->gr_gid; - } - if (setgid(gid) < 0) { - fprintf(stderr, - "%s: Unable to change to " - "group \"%s\".\n", - argv[0], config.group); - exit(EX_CANTCREAT); - } - log_message(LOG_INFO, "Now running as group \"%s\".", - config.group); - } - if (config.user && strlen(config.user) > 0) { - int uid = get_id(config.user); - if (uid < 0) { - thisuser = getpwnam(config.user); - if (!thisuser) { - fprintf(stderr, - "%s: Unable to find " - "user \"%s\".", - argv[0], config.user); - exit(EX_NOUSER); - } - uid = thisuser->pw_uid; - } - if (setuid(uid) < 0) { - fprintf(stderr, - "%s: Unable to change to user \"%s\".", - argv[0], config.user); - exit(EX_CANTCREAT); - } - 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) { - fprintf(stderr, "%s: Could not create the pool of children.", - argv[0]); - exit(EX_SOFTWARE); - } - - /* - * These signals are only for the parent process. - */ - log_message(LOG_INFO, "Setting the various signals."); - if (set_signal_handler(SIGCHLD, takesig) == SIG_ERR) { - fprintf(stderr, "%s: Could not set the \"SIGCHLD\" signal.\n", - argv[0]); - exit(EX_OSERR); - } - if (set_signal_handler(SIGTERM, takesig) == SIG_ERR) { - fprintf(stderr, "%s: Could not set the \"SIGTERM\" signal.\n", - argv[0]); - exit(EX_OSERR); - } - if (set_signal_handler(SIGHUP, takesig) == SIG_ERR) { - fprintf(stderr, "%s: Could not set the \"SIGHUP\" signal.\n", - argv[0]); - exit(EX_OSERR); - } - - /* - * Start the main loop. - */ - log_message(LOG_INFO, "Starting main loop. Accepting connections."); - - child_main_loop(); - - log_message(LOG_INFO, "Shutting down."); - - child_kill_children(); - child_close_sock(); - - /* - * Remove the PID file. - */ - if (unlink(config.pidpath) < 0) { - log_message(LOG_WARNING, - "Could not remove PID file \"%s\": %s.", - config.pidpath, strerror(errno)); - } + if (config.filter) + filter_init (); +#endif /* FILTER_ENABLE */ + + /* + * Start listening on the selected port. + */ + if (child_listening_sock (config.port) < 0) + { + fprintf (stderr, "%s: Could not create listening socket.\n", argv[0]); + exit (EX_OSERR); + } + + /* + * Switch to a different user. + */ + if (geteuid () == 0) + { + if (config.group && strlen (config.group) > 0) + { + int gid = get_id (config.group); + if (gid < 0) + { + thisgroup = getgrnam (config.group); + if (!thisgroup) + { + fprintf (stderr, + "%s: Unable to find " + "group \"%s\".\n", argv[0], config.group); + exit (EX_NOUSER); + } + gid = thisgroup->gr_gid; + } + if (setgid (gid) < 0) + { + fprintf (stderr, + "%s: Unable to change to " + "group \"%s\".\n", argv[0], config.group); + exit (EX_CANTCREAT); + } + log_message (LOG_INFO, "Now running as group \"%s\".", + config.group); + } + if (config.user && strlen (config.user) > 0) + { + int uid = get_id (config.user); + if (uid < 0) + { + thisuser = getpwnam (config.user); + if (!thisuser) + { + fprintf (stderr, + "%s: Unable to find " + "user \"%s\".", argv[0], config.user); + exit (EX_NOUSER); + } + uid = thisuser->pw_uid; + } + if (setuid (uid) < 0) + { + fprintf (stderr, + "%s: Unable to change to user \"%s\".", + argv[0], config.user); + exit (EX_CANTCREAT); + } + 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) + { + fprintf (stderr, "%s: Could not create the pool of children.", argv[0]); + exit (EX_SOFTWARE); + } + + /* + * These signals are only for the parent process. + */ + log_message (LOG_INFO, "Setting the various signals."); + if (set_signal_handler (SIGCHLD, takesig) == SIG_ERR) + { + fprintf (stderr, "%s: Could not set the \"SIGCHLD\" signal.\n", + argv[0]); + exit (EX_OSERR); + } + if (set_signal_handler (SIGTERM, takesig) == SIG_ERR) + { + fprintf (stderr, "%s: Could not set the \"SIGTERM\" signal.\n", + argv[0]); + exit (EX_OSERR); + } + if (set_signal_handler (SIGHUP, takesig) == SIG_ERR) + { + fprintf (stderr, "%s: Could not set the \"SIGHUP\" signal.\n", argv[0]); + exit (EX_OSERR); + } + + /* + * Start the main loop. + */ + log_message (LOG_INFO, "Starting main loop. Accepting connections."); + + child_main_loop (); + + log_message (LOG_INFO, "Shutting down."); + + child_kill_children (); + child_close_sock (); + + /* + * Remove the PID file. + */ + if (unlink (config.pidpath) < 0) + { + log_message (LOG_WARNING, + "Could not remove PID file \"%s\": %s.", + config.pidpath, strerror (errno)); + } #ifdef FILTER_ENABLE - if (config.filter) - filter_destroy(); -#endif /* FILTER_ENABLE */ + if (config.filter) + filter_destroy (); +#endif /* FILTER_ENABLE */ - if (config.syslog) - closelog(); - else - close_log_file(); + if (config.syslog) + closelog (); + else + close_log_file (); - exit(EX_OK); + exit (EX_OK); } diff --git a/src/tinyproxy.h b/src/tinyproxy.h index 88ed541..fe73da7 100644 --- a/src/tinyproxy.h +++ b/src/tinyproxy.h @@ -26,82 +26,84 @@ #include "hashmap.h" /* Global variables for the main controls of the program */ -#define MAXBUFFSIZE ((size_t)(1024 * 96)) /* Max size of buffer */ -#define MAX_IDLE_TIME (60 * 10) /* 10 minutes of no activity */ +#define MAXBUFFSIZE ((size_t)(1024 * 96)) /* Max size of buffer */ +#define MAX_IDLE_TIME (60 * 10) /* 10 minutes of no activity */ /* * Even if upstream support is not compiled into tinyproxy, this * structure still needs to be defined. */ -struct upstream { - struct upstream *next; - char *domain; /* optional */ - char *host; - int port; - in_addr_t ip, mask; +struct upstream +{ + struct upstream *next; + char *domain; /* optional */ + char *host; + int port; + in_addr_t ip, mask; }; /* * Hold all the configuration time information. */ -struct config_s { - char *logf_name; - char *config_file; - unsigned int syslog; /* boolean */ - int port; - char *stathost; - unsigned int quit; /* boolean */ - char *user; - char *group; - char *ipAddr; +struct config_s +{ + char *logf_name; + char *config_file; + unsigned int syslog; /* boolean */ + int port; + char *stathost; + unsigned int quit; /* boolean */ + char *user; + char *group; + char *ipAddr; #ifdef FILTER_ENABLE - char *filter; - unsigned int filter_url; /* boolean */ - unsigned int filter_extended; /* boolean */ - unsigned int filter_casesensitive; /* boolean */ -#endif /* FILTER_ENABLE */ + char *filter; + unsigned int filter_url; /* boolean */ + unsigned int filter_extended; /* boolean */ + unsigned int filter_casesensitive; /* boolean */ +#endif /* FILTER_ENABLE */ #ifdef XTINYPROXY_ENABLE - char *my_domain; + char *my_domain; #endif #ifdef REVERSE_SUPPORT - struct reversepath *reversepath_list; - unsigned int reverseonly; /* boolean */ - unsigned int reversemagic; /* boolean */ - char *reversebaseurl; + struct reversepath *reversepath_list; + unsigned int reverseonly; /* boolean */ + unsigned int reversemagic; /* boolean */ + char *reversebaseurl; #endif #ifdef UPSTREAM_SUPPORT - struct upstream *upstream_list; -#endif /* UPSTREAM_SUPPORT */ - char *pidpath; - unsigned int idletimeout; - char *bind_address; - unsigned int bindsame; + struct upstream *upstream_list; +#endif /* UPSTREAM_SUPPORT */ + char *pidpath; + unsigned int idletimeout; + char *bind_address; + unsigned int bindsame; - /* - * The configured name to use in the HTTP "Via" header field. - */ - char *via_proxy_name; + /* + * The configured name to use in the HTTP "Via" header field. + */ + char *via_proxy_name; - /* - * Error page support. Map error numbers to file paths. - */ - hashmap_t errorpages; + /* + * Error page support. Map error numbers to file paths. + */ + hashmap_t errorpages; - /* - * Error page to be displayed if appropriate page cannot be located - * in the errorpages structure. - */ - char *errorpage_undef; + /* + * Error page to be displayed if appropriate page cannot be located + * in the errorpages structure. + */ + char *errorpage_undef; - /* - * The HTML statistics page. - */ - char *statpage; + /* + * The HTML statistics page. + */ + char *statpage; }; /* Global Structures used in the program */ extern struct config_s config; -extern unsigned int received_sighup; /* boolean */ -extern unsigned int processed_config_file; /* boolean */ +extern unsigned int received_sighup; /* boolean */ +extern unsigned int processed_config_file; /* boolean */ #endif diff --git a/src/transparent-proxy.c b/src/transparent-proxy.c index 5bffa31..b089030 100644 --- a/src/transparent-proxy.c +++ b/src/transparent-proxy.c @@ -36,86 +36,86 @@ * Build a URL from parts. */ 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(host != NULL); - assert(port > 0 && port < 32768); - assert(path != NULL); + assert (url != NULL); + assert (host != NULL); + assert (port > 0 && port < 32768); + assert (path != NULL); - len = strlen(host) + strlen(path) + 14; - *url = safemalloc(len); - if (*url == NULL) - return -1; + len = strlen (host) + strlen (path) + 14; + *url = safemalloc (len); + if (*url == NULL) + 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 -do_transparent_proxy(struct conn_s *connptr, hashmap_t hashofheaders, - struct request_s *request, struct config_s *conf, char *url) +do_transparent_proxy (struct conn_s *connptr, hashmap_t hashofheaders, + struct request_s *request, struct config_s *conf, + char *url) { - socklen_t length; - 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; - } + socklen_t length; + char *data; - 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; } diff --git a/src/transparent-proxy.h b/src/transparent-proxy.h index 37cc54d..09a7777 100644 --- a/src/transparent-proxy.h +++ b/src/transparent-proxy.h @@ -29,9 +29,10 @@ #include "hashmap.h" #include "reqs.h" -extern int do_transparent_proxy(struct conn_s *connptr, - hashmap_t hashofheaders, struct request_s *request, - struct config_s *config, char *url); +extern int do_transparent_proxy (struct conn_s *connptr, + hashmap_t hashofheaders, + struct request_s *request, + struct config_s *config, char *url); #endif diff --git a/src/utils.c b/src/utils.c index 0f4acaa..5064555 100644 --- a/src/utils.c +++ b/src/utils.c @@ -34,175 +34,183 @@ * Build the data for a complete HTTP & HTML message for the client. */ int -send_http_message(struct conn_s *connptr, int http_code, - const char *error_title, const char *message) +send_http_message (struct conn_s *connptr, int http_code, + const char *error_title, const char *message) { - static char *headers[] = { - "Server: " PACKAGE "/" VERSION, - "Content-type: text/html", - "Connection: close" - }; + static char *headers[] = { + "Server: " PACKAGE "/" VERSION, + "Content-type: text/html", + "Connection: close" + }; - http_message_t msg; + http_message_t msg; - msg = http_message_create(http_code, error_title); - if (msg == NULL) - return -1; + msg = http_message_create (http_code, error_title); + if (msg == NULL) + return -1; - http_message_add_headers(msg, headers, 3); - http_message_set_body(msg, message, strlen(message)); - http_message_send(msg, connptr->client_fd); - http_message_destroy(msg); + http_message_add_headers (msg, headers, 3); + http_message_set_body (msg, message, strlen (message)); + http_message_send (msg, connptr->client_fd); + http_message_destroy (msg); - return 0; + return 0; } /* * Safely creates filename and returns the low-level file descriptor. */ int -create_file_safely(const char *filename, unsigned int truncate_file) +create_file_safely (const char *filename, unsigned int truncate_file) { - struct stat lstatinfo; - int fildes; - - /* - * 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() - * check. - */ - if (lstat(filename, &lstatinfo) < 0) { - /* - * If lstat() failed for any reason other than "file not - * existing", exit. - */ - if (errno != ENOENT) { - fprintf(stderr, - "%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 - * sure an attacker can't slip in a file between the lstat() - * and open() - */ - if ((fildes = - open(filename, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0) { - fprintf(stderr, - "%s: Could not create file %s: %s\n", - PACKAGE, filename, strerror(errno)); - return fildes; - } - } else { - struct stat fstatinfo; - int flags; - - flags = O_RDWR; - if (!truncate_file) - flags |= O_APPEND; - - /* - * Open an existing file. - */ - if ((fildes = open(filename, flags)) < 0) { - fprintf(stderr, - "%s: Could not open file %s: %s\n", - PACKAGE, filename, strerror(errno)); - return fildes; - } - - /* - * fstat() the opened file and check that the file mode bits, - * inode, and device match. - */ - if (fstat(fildes, &fstatinfo) < 0 - || lstatinfo.st_mode != fstatinfo.st_mode - || lstatinfo.st_ino != fstatinfo.st_ino - || lstatinfo.st_dev != fstatinfo.st_dev) { - fprintf(stderr, - "%s: The file %s has been changed before it could be opened\n", - PACKAGE, filename); - close(fildes); - return -EIO; - } - - /* - * If the above check was passed, we know that the lstat() - * 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 - * isn't strictly necessary because the fstat() vs lstat() - * st_mode check would also find this) - */ - 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", - PACKAGE, filename, strerror(errno)); - close(fildes); - return -EMLINK; - } - - /* - * Just return the file descriptor if we _don't_ want the file - * truncated. - */ - if (!truncate_file) - return fildes; - - /* - * On systems which don't support ftruncate() the best we can - * do is to close the file and reopen it in create mode, which - * unfortunately leads to a race condition, however "systems - * which don't support ftruncate()" is pretty much SCO only, - * and if you're using that you deserve what you get. - * ("Little sympathy has been extended") - */ + struct stat lstatinfo; + int fildes; + + /* + * 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() + * check. + */ + if (lstat (filename, &lstatinfo) < 0) + { + /* + * If lstat() failed for any reason other than "file not + * existing", exit. + */ + if (errno != ENOENT) + { + fprintf (stderr, + "%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 + * sure an attacker can't slip in a file between the lstat() + * and open() + */ + if ((fildes = open (filename, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0) + { + fprintf (stderr, + "%s: Could not create file %s: %s\n", + PACKAGE, filename, strerror (errno)); + return fildes; + } + } + else + { + struct stat fstatinfo; + int flags; + + flags = O_RDWR; + if (!truncate_file) + flags |= O_APPEND; + + /* + * Open an existing file. + */ + if ((fildes = open (filename, flags)) < 0) + { + fprintf (stderr, + "%s: Could not open file %s: %s\n", + PACKAGE, filename, strerror (errno)); + return fildes; + } + + /* + * fstat() the opened file and check that the file mode bits, + * inode, and device match. + */ + if (fstat (fildes, &fstatinfo) < 0 + || lstatinfo.st_mode != fstatinfo.st_mode + || lstatinfo.st_ino != fstatinfo.st_ino + || lstatinfo.st_dev != fstatinfo.st_dev) + { + fprintf (stderr, + "%s: The file %s has been changed before it could be opened\n", + PACKAGE, filename); + close (fildes); + return -EIO; + } + + /* + * If the above check was passed, we know that the lstat() + * 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 + * isn't strictly necessary because the fstat() vs lstat() + * st_mode check would also find this) + */ + 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", + PACKAGE, filename, strerror (errno)); + close (fildes); + return -EMLINK; + } + + /* + * Just return the file descriptor if we _don't_ want the file + * truncated. + */ + if (!truncate_file) + return fildes; + + /* + * On systems which don't support ftruncate() the best we can + * do is to close the file and reopen it in create mode, which + * unfortunately leads to a race condition, however "systems + * which don't support ftruncate()" is pretty much SCO only, + * and if you're using that you deserve what you get. + * ("Little sympathy has been extended") + */ #ifdef HAVE_FTRUNCATE - ftruncate(fildes, 0); + ftruncate (fildes, 0); #else - close(fildes); - if ((fildes = - open(filename, O_RDWR | O_CREAT | O_TRUNC, 0600)) < 0) { - fprintf(stderr, - "%s: Could not open file %s: %s.", - PACKAGE, filename, strerror(errno)); - return fildes; - } -#endif /* HAVE_FTRUNCATE */ - } - - return fildes; + close (fildes); + if ((fildes = open (filename, O_RDWR | O_CREAT | O_TRUNC, 0600)) < 0) + { + fprintf (stderr, + "%s: Could not open file %s: %s.", + PACKAGE, filename, strerror (errno)); + return fildes; + } +#endif /* HAVE_FTRUNCATE */ + } + + return fildes; } /* * Write the PID of the program to the specified file. */ int -pidfile_create(const char *filename) +pidfile_create (const char *filename) { - int fildes; - FILE *fd; - - /* - * Create a new file - */ - if ((fildes = create_file_safely(filename, TRUE)) < 0) - return fildes; - - /* - * Open a stdio file over the low-level one. - */ - if ((fd = fdopen(fildes, "w")) == NULL) { - fprintf(stderr, - "%s: Could not write PID file %s: %s.", - PACKAGE, filename, strerror(errno)); - close(fildes); - unlink(filename); - return -EIO; - } - - fprintf(fd, "%ld\n", (long)getpid()); - fclose(fd); - return 0; + int fildes; + FILE *fd; + + /* + * Create a new file + */ + if ((fildes = create_file_safely (filename, TRUE)) < 0) + return fildes; + + /* + * Open a stdio file over the low-level one. + */ + if ((fd = fdopen (fildes, "w")) == NULL) + { + fprintf (stderr, + "%s: Could not write PID file %s: %s.", + PACKAGE, filename, strerror (errno)); + close (fildes); + unlink (filename); + return -EIO; + } + + fprintf (fd, "%ld\n", (long) getpid ()); + fclose (fd); + return 0; } diff --git a/src/utils.h b/src/utils.h index 81172e2..784a2ac 100644 --- a/src/utils.h +++ b/src/utils.h @@ -27,10 +27,11 @@ */ struct conn_s; -extern int send_http_message(struct conn_s *connptr, int http_code, - const char *error_title, const char *message); +extern int send_http_message (struct conn_s *connptr, int http_code, + const char *error_title, const char *message); -extern int pidfile_create(const char *path); -extern int create_file_safely(const char *filename, unsigned int truncate_file); +extern int pidfile_create (const char *path); +extern int create_file_safely (const char *filename, + unsigned int truncate_file); #endif diff --git a/src/vector.c b/src/vector.c index e9ca586..a68fddc 100644 --- a/src/vector.c +++ b/src/vector.c @@ -33,17 +33,19 @@ * 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.) */ -struct vectorentry_s { - void *data; - size_t len; +struct vectorentry_s +{ + void *data; + size_t len; - struct vectorentry_s *next; + struct vectorentry_s *next; }; -struct vector_s { - size_t num_entries; - struct vectorentry_s *head; - struct vectorentry_s *tail; +struct vector_s +{ + size_t num_entries; + struct vectorentry_s *head; + struct vectorentry_s *tail; }; /* @@ -54,18 +56,18 @@ struct vector_s { * vector. */ vector_t -vector_create(void) +vector_create (void) { - vector_t vector; + vector_t vector; - vector = safemalloc(sizeof(struct vector_s)); - if (!vector) - return NULL; + vector = safemalloc (sizeof (struct vector_s)); + if (!vector) + return NULL; - vector->num_entries = 0; - vector->head = vector->tail = NULL; + vector->num_entries = 0; + vector->head = vector->tail = NULL; - return vector; + return vector; } /* @@ -75,25 +77,26 @@ vector_create(void) * negative if a NULL vector is supplied */ int -vector_delete(vector_t vector) +vector_delete (vector_t vector) { - struct vectorentry_s *ptr, *next; + struct vectorentry_s *ptr, *next; - if (!vector) - return -EINVAL; + if (!vector) + return -EINVAL; - ptr = vector->head; - while (ptr) { - next = ptr->next; - safefree(ptr->data); - safefree(ptr); + ptr = vector->head; + while (ptr) + { + next = ptr->next; + 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 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; - - if (!vector || !data || len <= 0 || - (pos != INSERT_PREPEND && pos != INSERT_APPEND)) - return -EINVAL; - - entry = safemalloc(sizeof(struct vectorentry_s)); - if (!entry) - return -ENOMEM; - - entry->data = safemalloc(len); - if (!entry->data) { - safefree(entry); - return -ENOMEM; - } - - memcpy(entry->data, data, len); - entry->len = len; - entry->next = NULL; - - /* If there is no head or tail, create them */ - if (!vector->head && !vector->tail) - vector->head = vector->tail = entry; - else if (pos == 0) { - /* prepend the entry */ - entry->next = vector->head; - vector->head = entry; - } else { - /* append the entry */ - vector->tail->next = entry; - vector->tail = entry; - } - - vector->num_entries++; - - return 0; + struct vectorentry_s *entry; + + if (!vector || !data || len <= 0 || + (pos != INSERT_PREPEND && pos != INSERT_APPEND)) + return -EINVAL; + + entry = safemalloc (sizeof (struct vectorentry_s)); + if (!entry) + return -ENOMEM; + + entry->data = safemalloc (len); + if (!entry->data) + { + safefree (entry); + return -ENOMEM; + } + + memcpy (entry->data, data, len); + entry->len = len; + entry->next = NULL; + + /* If there is no head or tail, create them */ + if (!vector->head && !vector->tail) + vector->head = vector->tail = entry; + else if (pos == 0) + { + /* prepend the entry */ + entry->next = vector->head; + vector->head = entry; + } + else + { + /* append the entry */ + vector->tail->next = entry; + vector->tail = entry; + } + + vector->num_entries++; + + return 0; } /* @@ -156,15 +163,15 @@ vector_insert(vector_t vector, void *data, ssize_t len, int pos) * arguments. */ 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 -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 */ 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; - size_t loc; + struct vectorentry_s *ptr; + size_t loc; - if (!vector || pos >= vector->num_entries) - return NULL; + if (!vector || pos >= vector->num_entries) + return NULL; - loc = 0; - ptr = vector->head; + loc = 0; + ptr = vector->head; - while (loc != pos) { - ptr = ptr->next; - loc++; - } + while (loc != pos) + { + ptr = ptr->next; + loc++; + } - if (size) - *size = ptr->len; + if (size) + *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 */ ssize_t -vector_length(vector_t vector) +vector_length (vector_t vector) { - if (!vector) - return -EINVAL; + if (!vector) + return -EINVAL; - return vector->num_entries; + return vector->num_entries; } diff --git a/src/vector.h b/src/vector.h index ad40bf0..f319cad 100644 --- a/src/vector.h +++ b/src/vector.h @@ -23,7 +23,8 @@ /* Allow the use in C++ code. */ #if defined(__cplusplus) -extern "C" { +extern "C" +{ #endif /* @@ -31,14 +32,14 @@ extern "C" { * 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. :) */ - typedef struct vector_s *vector_t; + typedef struct vector_s *vector_t; /* * vector_create() takes no arguments. * vector_delete() is self explanatory. */ - extern vector_t vector_create(void); - extern int vector_delete(vector_t vector); + extern vector_t vector_create (void); + extern int vector_delete (vector_t vector); /* * When you insert a piece of data into the vector, the data will be @@ -48,8 +49,8 @@ extern "C" { * Returns: negative on error * 0 upon successful insert. */ - 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_append (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 @@ -67,8 +68,7 @@ extern "C" { * Returns: NULL on error * valid pointer to data */ - extern void *vector_getentry(vector_t vector, size_t pos, - size_t * size); + extern void *vector_getentry (vector_t vector, size_t pos, size_t * size); /* * Returns the number of enteries (or the length) of the vector. @@ -76,9 +76,9 @@ extern "C" { * Returns: negative if vector is not valid * positive length of vector otherwise */ - extern ssize_t vector_length(vector_t vector); + extern ssize_t vector_length (vector_t vector); #if defined(__cplusplus) } -#endif /* C++ */ -#endif /* _VECTOR_H */ +#endif /* C++ */ +#endif /* _VECTOR_H */ |