summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am1
-rw-r--r--src/child.c3
-rw-r--r--src/loop.c76
-rw-r--r--src/loop.h11
-rw-r--r--src/reqs.c15
-rw-r--r--src/sock.c12
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
+
diff --git a/src/reqs.c b/src/reqs.c
index c576412..3adc473 100644
--- a/src/reqs.c
+++ b/src/reqs.c
@@ -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",
diff --git a/src/sock.c b/src/sock.c
index f74a588..8513ba8 100644
--- a/src/sock.c
+++ b/src/sock.c
@@ -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);