diff options
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/child.c | 3 | ||||
-rw-r--r-- | src/loop.c | 76 | ||||
-rw-r--r-- | src/loop.h | 11 | ||||
-rw-r--r-- | src/reqs.c | 15 | ||||
-rw-r--r-- | src/sock.c | 12 |
6 files changed, 117 insertions, 1 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 3924909..50e645b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -49,6 +49,7 @@ tinyproxy_SOURCES = \ basicauth.c basicauth.h \ base64.c base64.h \ sblist.c sblist.h \ + loop.c loop.h \ connect-ports.c connect-ports.h EXTRA_tinyproxy_SOURCES = filter.c filter.h \ diff --git a/src/child.c b/src/child.c index 8bd713d..861606b 100644 --- a/src/child.c +++ b/src/child.c @@ -32,6 +32,7 @@ #include "utils.h" #include "conf.h" #include "sblist.h" +#include "loop.h" #include <pthread.h> static vector_t listen_fds; @@ -87,6 +88,8 @@ void child_main_loop (void) childs = sblist_new(sizeof (struct child*), config.maxclients); + loop_records_init(); + /* * We have to wait for connections on multiple fds, * so use select. diff --git a/src/loop.c b/src/loop.c new file mode 100644 index 0000000..77b073d --- /dev/null +++ b/src/loop.c @@ -0,0 +1,76 @@ +#include <pthread.h> +#include <time.h> +#include "loop.h" +#include "conf.h" +#include "main.h" +#include "sblist.h" +#include "sock.h" + +struct loop_record { + union sockaddr_union addr; + time_t tstamp; +}; + +static sblist *loop_records; +static pthread_mutex_t loop_records_lock = PTHREAD_MUTEX_INITIALIZER; + +void loop_records_init(void) { + loop_records = sblist_new(sizeof (struct loop_record), 32); +} + +#if 0 +static void su_to_str(union sockaddr_union *addr, char *buf) { + int af = addr->v4.sin_family; + unsigned port = ntohs(af == AF_INET ? addr->v4.sin_port : addr->v6.sin6_port); + char portb[32]; + sprintf(portb, ":%u", port); + getpeer_information (addr, buf, 256); + strcat(buf, portb); +} +#endif + +void loop_records_add(union sockaddr_union *addr) { + time_t now =time(0); + struct loop_record rec; + pthread_mutex_lock(&loop_records_lock); + rec.tstamp = now; + rec.addr = *addr; + sblist_add(loop_records, &rec); + pthread_mutex_unlock(&loop_records_lock); +} + +#define TIMEOUT_SECS 15 + +int connection_loops (union sockaddr_union *addr) { + int ret = 0, af, our_af = addr->v4.sin_family; + void *ipdata, *our_ipdata = our_af == AF_INET ? (void*)&addr->v4.sin_addr.s_addr : (void*)&addr->v6.sin6_addr.s6_addr; + size_t i, cmp_len = our_af == AF_INET ? sizeof(addr->v4.sin_addr.s_addr) : sizeof(addr->v6.sin6_addr.s6_addr); + unsigned port, our_port = ntohs(our_af == AF_INET ? addr->v4.sin_port : addr->v6.sin6_port); + time_t now = time(0); + + pthread_mutex_lock(&loop_records_lock); + for (i = 0; i < sblist_getsize(loop_records); ) { + struct loop_record *rec = sblist_get(loop_records, i); + + if (rec->tstamp + TIMEOUT_SECS < now) { + sblist_delete(loop_records, i); + continue; + } + + if (!ret) { + af = rec->addr.v4.sin_family; + if (af != our_af) goto next; + port = ntohs(af == AF_INET ? rec->addr.v4.sin_port : rec->addr.v6.sin6_port); + if (port != our_port) goto next; + ipdata = af == AF_INET ? (void*)&rec->addr.v4.sin_addr.s_addr : (void*)&rec->addr.v6.sin6_addr.s6_addr; + if (!memcmp(ipdata, our_ipdata, cmp_len)) { + ret = 1; + } + } +next: + i++; + } + pthread_mutex_unlock(&loop_records_lock); + return ret; +} + diff --git a/src/loop.h b/src/loop.h new file mode 100644 index 0000000..19877d3 --- /dev/null +++ b/src/loop.h @@ -0,0 +1,11 @@ +#ifndef LOOP_H +#define LOOP_H + +#include "sock.h" + +void loop_records_init(void); +void loop_records_add(union sockaddr_union *addr); +int connection_loops (union sockaddr_union *addr); + +#endif + @@ -49,6 +49,7 @@ #include "connect-ports.h" #include "conf.h" #include "basicauth.h" +#include "loop.h" /* * Maximum length of a HTTP line @@ -1560,6 +1561,20 @@ void handle_connection (int fd, union sockaddr_union* addr) return; } + if (connection_loops (addr)) { + log_message (LOG_CONN, + "Prevented endless loop (file descriptor %d): %s", + fd, peer_ipaddr); + + indicate_http_error(connptr, 400, "Bad Request", + "detail", + "You tried to connect to the " + "machine the proxy is running on", + NULL); + goto fail; + } + + if (check_acl (peer_ipaddr, addr, config.access_list) <= 0) { update_stats (STAT_DENIED); indicate_http_error (connptr, 403, "Access denied", @@ -33,6 +33,7 @@ #include "sock.h" #include "text.h" #include "conf.h" +#include "loop.h" /* * Return a human readable error for getaddrinfo() and getnameinfo(). @@ -141,8 +142,17 @@ int opensock (const char *host, int port, const char *bind_to) } } - if (connect (sockfd, res->ai_addr, res->ai_addrlen) == 0) + if (connect (sockfd, res->ai_addr, res->ai_addrlen) == 0) { + union sockaddr_union *p = (void*) res->ai_addr, u; + int af = res->ai_addr->sa_family; + unsigned dport = ntohs(af == AF_INET ? p->v4.sin_port : p->v6.sin6_port); + socklen_t slen = sizeof u; + if (dport == config.port) { + getsockname(sockfd, (void*)&u, &slen); + loop_records_add(&u); + } break; /* success */ + } close (sockfd); } while ((res = res->ai_next) != NULL); |