about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRichard Nyberg <rnyberg@murmeldjur.se>2006-07-22 20:44:12 +0000
committerRichard Nyberg <rnyberg@murmeldjur.se>2006-07-22 20:44:12 +0000
commit2a462baead6ed9925c5e86578b8381f1b905ae34 (patch)
treeeabd96f239bb34824ca4c622bde689fe8c17720e
parentcfb37a5227c6599a3a7a5179c9c428bb07cde5ed (diff)
downloadbtpd-2a462baead6ed9925c5e86578b8381f1b905ae34.tar.gz
btpd-2a462baead6ed9925c5e86578b8381f1b905ae34.zip
Btpd could be DOS'ed by incoming connections that never send any data.
Strangely such connections are not entirely uncommon. Added a hand shake
time out of 60 seconds to resolve this.

Added a peer_on_tick function which is used to monitor peers for different
timeouts. Timestamps are compared against the reborn btpd_seconds.

The issue has been reported by Ludvig Omholt and Arnaud Bergeron.

-rw-r--r--btpd/btpd.c13
-rw-r--r--btpd/btpd.h2
-rw-r--r--btpd/net.c57
-rw-r--r--btpd/net.h4
-rw-r--r--btpd/net_types.h3
-rw-r--r--btpd/peer.c16
-rw-r--r--btpd/peer.h1
7 files changed, 71 insertions, 25 deletions
diff --git a/btpd/btpd.c b/btpd/btpd.c
index 4345303..c41d208 100644
--- a/btpd/btpd.c
+++ b/btpd/btpd.c
@@ -32,8 +32,11 @@
 static uint8_t m_peer_id[20];
 static struct event m_sigint;
 static struct event m_sigterm;
+static struct event m_heartbeat;
 static int m_shutdown;
 
+long btpd_seconds;
+
 void
 btpd_exit(int code)
 {
@@ -92,6 +95,14 @@ signal_cb(int signal, short type, void *arg)
     btpd_shutdown(30);
 }
 
+static void
+heartbeat_cb(int fd, short type, void *arg)
+{
+    btpd_ev_add(&m_heartbeat, (& (struct timeval) { 1, 0 }));
+    btpd_seconds++;
+    net_on_tick();
+}
+
 struct td_cb {
     void (*cb)(void *);
     void *arg;
@@ -196,4 +207,6 @@ btpd_init(void)
     btpd_ev_add(&m_sigint, NULL);
     signal_set(&m_sigterm, SIGTERM, signal_cb, NULL);
     btpd_ev_add(&m_sigterm, NULL);
+    evtimer_set(&m_heartbeat, heartbeat_cb, NULL);
+    btpd_ev_add(&m_heartbeat, (& (struct timeval) { 1, 0 }));
 }
diff --git a/btpd/btpd.h b/btpd/btpd.h
index 9c64b51..55f235f 100644
--- a/btpd/btpd.h
+++ b/btpd/btpd.h
@@ -39,6 +39,8 @@
 #define BTPD_L_BTPD     0x00000010
 #define BTPD_L_POL      0x00000020
 
+extern long btpd_seconds;
+
 void btpd_init(void);
 
 void btpd_log(uint32_t type, const char *fmt, ...);
diff --git a/btpd/net.c b/btpd/net.c
index 66130b0..1aa7bd9 100644
--- a/btpd/net.c
+++ b/btpd/net.c
@@ -18,7 +18,6 @@
 
 #include "btpd.h"
 
-static struct event m_bw_timer;
 static unsigned long m_bw_bytes_in;
 static unsigned long m_bw_bytes_out;
 
@@ -178,7 +177,8 @@ net_write(struct peer *p, unsigned long wmax)
     nwritten = writev(p->sd, iov, niov);
     if (nwritten < 0) {
         if (errno == EAGAIN) {
-            btpd_ev_add(&p->out_ev, WRITE_TIMEOUT);
+            btpd_ev_add(&p->out_ev, NULL);
+            p->t_wantwrite = btpd_seconds;
             return 0;
         } else {
             btpd_log(BTPD_L_CONN, "write error: %s\n", strerror(errno));
@@ -217,8 +217,10 @@ net_write(struct peer *p, unsigned long wmax)
             bcount = 0;
         }
     }
-    if (!BTPDQ_EMPTY(&p->outq))
-        btpd_ev_add(&p->out_ev, WRITE_TIMEOUT);
+    if (!BTPDQ_EMPTY(&p->outq)) {
+        btpd_ev_add(&p->out_ev, NULL);
+        p->t_wantwrite = btpd_seconds;
+    }
 
     return nwritten;
 }
@@ -570,15 +572,11 @@ compute_rates(void) {
     m_rate_dwn += tot_dwn - compute_rate_sub(m_rate_dwn);
 }
 
-void
-net_bw_cb(int sd, short type, void *arg)
+static void
+net_bw_tick(void)
 {
     struct peer *p;
 
-    btpd_ev_add(&m_bw_timer, (& (struct timeval) { 1, 0 }));
-
-    compute_rates();
-
     m_bw_bytes_out = net_bw_limit_out;
     m_bw_bytes_in = net_bw_limit_in;
 
@@ -597,7 +595,8 @@ net_bw_cb(int sd, short type, void *arg)
     }
 
     if (net_bw_limit_out) {
-        while ((p = BTPDQ_FIRST(&net_bw_writeq)) != NULL && m_bw_bytes_out > 0) {
+        while (((p = BTPDQ_FIRST(&net_bw_writeq)) != NULL
+                   && m_bw_bytes_out > 0)) {
             BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry);
             p->flags &= ~PF_ON_WRITEQ;
             m_bw_bytes_out -=  net_write(p, m_bw_bytes_out);
@@ -611,6 +610,28 @@ net_bw_cb(int sd, short type, void *arg)
     }
 }
 
+static void
+run_peer_ticks(void)
+{
+    struct net *n;
+    struct peer *p, *next;
+
+    BTPDQ_FOREACH_MUTABLE(p, &net_unattached, p_entry, next)
+        peer_on_tick(p);
+
+    BTPDQ_FOREACH(n, &m_torrents, entry)
+        BTPDQ_FOREACH_MUTABLE(p, &n->peers, p_entry, next)
+            peer_on_tick(p);
+}
+
+void
+net_on_tick(void)
+{
+    run_peer_ticks();
+    compute_rates();
+    net_bw_tick();
+}
+
 void
 net_read_cb(int sd, short type, void *arg)
 {
@@ -629,16 +650,11 @@ void
 net_write_cb(int sd, short type, void *arg)
 {
     struct peer *p = (struct peer *)arg;
-    if (type == EV_TIMEOUT) {
-        btpd_log(BTPD_L_CONN, "Write attempt timed out.\n");
-        peer_kill(p);
-        return;
-    }
-    if (net_bw_limit_out == 0) {
+    if (net_bw_limit_out == 0)
         net_write(p, 0);
-    } else if (m_bw_bytes_out > 0) {
+    else if (m_bw_bytes_out > 0)
         m_bw_bytes_out -= net_write(p, m_bw_bytes_out);
-    } else {
+    else {
         p->flags |= PF_ON_WRITEQ;
         BTPDQ_INSERT_TAIL(&net_bw_writeq, p, wq_entry);
     }
@@ -672,7 +688,4 @@ net_init(void)
     event_set(&m_net_incoming, sd, EV_READ | EV_PERSIST,
         net_connection_cb, NULL);
     btpd_ev_add(&m_net_incoming, NULL);
-
-    evtimer_set(&m_bw_timer, net_bw_cb, NULL);
-    btpd_ev_add(&m_bw_timer, (& (struct timeval) { 1, 0 }));
 }
diff --git a/btpd/net.h b/btpd/net.h
index 793386e..bbc3ceb 100644
--- a/btpd/net.h
+++ b/btpd/net.h
@@ -11,8 +11,6 @@
 #define MSG_PIECE       7
 #define MSG_CANCEL      8
 
-#define WRITE_TIMEOUT (& (struct timeval) { 60, 0 })
-
 extern struct peer_tq net_unattached;
 extern struct peer_tq net_bw_readq;
 extern struct peer_tq net_bw_writeq;
@@ -20,6 +18,8 @@ extern unsigned net_npeers;
 
 void net_init(void);
 
+void net_on_tick(void);
+
 void net_create(struct torrent *tp);
 void net_kill(struct torrent *tp);
 
diff --git a/btpd/net_types.h b/btpd/net_types.h
index 5359867..b444eea 100644
--- a/btpd/net_types.h
+++ b/btpd/net_types.h
@@ -61,6 +61,9 @@ struct peer {
     unsigned long rate_up, rate_dwn;
     unsigned long count_up, count_dwn;
 
+    long t_created;
+    long t_wantwrite;
+
     struct {
         uint32_t msg_len;
         uint8_t msg_num;
diff --git a/btpd/peer.c b/btpd/peer.c
index 283200f..dce170f 100644
--- a/btpd/peer.c
+++ b/btpd/peer.c
@@ -66,7 +66,8 @@ peer_send(struct peer *p, struct net_buf *nb)
 
     if (BTPDQ_EMPTY(&p->outq)) {
         assert(p->outq_off == 0);
-        btpd_ev_add(&p->out_ev, WRITE_TIMEOUT);
+        btpd_ev_add(&p->out_ev, NULL);
+        p->t_wantwrite = btpd_seconds;
     }
     BTPDQ_INSERT_TAIL(&p->outq, nl, entry);
 }
@@ -263,6 +264,7 @@ peer_create_common(int sd)
 
     p->sd = sd;
     p->flags = PF_I_CHOKE | PF_P_CHOKE;
+    p->t_created = btpd_seconds;
     BTPDQ_INIT(&p->my_reqs);
     BTPDQ_INIT(&p->outq);
 
@@ -507,6 +509,18 @@ peer_on_cancel(struct peer *p, uint32_t index, uint32_t begin,
         }
 }
 
+void
+peer_on_tick(struct peer *p)
+{
+    if ((p->flags & PF_ATTACHED) == 0 && btpd_seconds - p->t_created >= 60) {
+        btpd_log(BTPD_L_CONN, "hand shake timed out.\n");
+        peer_kill(p);
+    } else if (!BTPDQ_EMPTY(&p->outq) && btpd_seconds - p->t_wantwrite >= 60) {
+        btpd_log(BTPD_L_CONN, "write attempt timed out.\n");
+        peer_kill(p);
+    }
+}
+
 int
 peer_chokes(struct peer *p)
 {
diff --git a/btpd/peer.h b/btpd/peer.h
index cdf1796..cce6841 100644
--- a/btpd/peer.h
+++ b/btpd/peer.h
@@ -52,6 +52,7 @@ void peer_on_request(struct peer *p, uint32_t index, uint32_t begin,
     uint32_t length);
 void peer_on_cancel(struct peer *p, uint32_t index, uint32_t begin,
     uint32_t length);
+void peer_on_tick(struct peer *p);
 
 int peer_active_down(struct peer *p);
 int peer_active_up(struct peer *p);