瀏覽代碼

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.
master
Richard Nyberg 18 年之前
父節點
當前提交
2a462baead
共有 7 個檔案被更改,包括 71 行新增25 行删除
  1. +13
    -0
      btpd/btpd.c
  2. +2
    -0
      btpd/btpd.h
  3. +35
    -22
      btpd/net.c
  4. +2
    -2
      btpd/net.h
  5. +3
    -0
      btpd/net_types.h
  6. +15
    -1
      btpd/peer.c
  7. +1
    -0
      btpd/peer.h

+ 13
- 0
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 }));
}

+ 2
- 0
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, ...);


+ 35
- 22
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 }));
}

+ 2
- 2
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);



+ 3
- 0
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;


+ 15
- 1
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)
{


+ 1
- 0
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);


Loading…
取消
儲存