Selaa lähdekoodia

Add IPv6 support.

Btpd can now use both ipv4 and ipv6. The new options -4 and -6 toggles
use of ip v4 and v6 respectively. They are both used by default.
Remove restrictions on the --ip option since the spec allows to be a
dns name. Ultimately this option may need to be changed on a per
tracker/torrent basis.
master
Richard Nyberg 16 vuotta sitten
vanhempi
commit
05329268d5
9 muutettua tiedostoa jossa 144 lisäystä ja 66 poistoa
  1. +21
    -14
      btpd/http_tr_if.c
  2. +19
    -14
      btpd/main.c
  3. +1
    -1
      btpd/nameconn.c
  4. +64
    -23
      btpd/net.c
  5. +5
    -2
      btpd/net.h
  6. +3
    -1
      btpd/opts.c
  7. +2
    -1
      btpd/opts.h
  8. +28
    -9
      btpd/peer.c
  9. +1
    -1
      btpd/peer.h

+ 21
- 14
btpd/http_tr_if.c Näytä tiedosto

@@ -62,6 +62,7 @@ parse_reply(struct torrent *tp, const char *content, size_t size, int parse,
const char *buf; const char *buf;
size_t len; size_t len;
const char *peers; const char *peers;
const char *v6key[] = {"peers6", "peers_ipv6"};


if (benc_validate(content, size) != 0) if (benc_validate(content, size) != 0)
goto bad_data; goto bad_data;
@@ -92,12 +93,24 @@ parse_reply(struct torrent *tp, const char *content, size_t size, int parse,
peers = benc_next(peers)) peers = benc_next(peers))
maybe_connect_to(tp, peers); maybe_connect_to(tp, peers);
} else if (benc_isstr(peers)) { } else if (benc_isstr(peers)) {
peers = benc_dget_mem(content, "peers", &len); if (net_ipv4) {
for (size_t i = 0; i < len && net_npeers < net_max_peers; i += 6) peers = benc_dget_mem(content, "peers", &len);
peer_create_out_compact(tp->net, peers + i); for (size_t i = 0; i < len && net_npeers < net_max_peers; i += 6)
peer_create_out_compact(tp->net, AF_INET, peers + i);
}
} else } else
goto bad_data; goto bad_data;


if (!net_ipv6)
return 0;
for (int k = 0; k < 2; k++) {
peers = benc_dget_any(content, v6key[k]);
if (peers != NULL && benc_isstr(peers)) {
peers = benc_dget_mem(content, v6key[k], &len);
for (size_t i = 0; i < len && net_npeers < net_max_peers; i += 18)
peer_create_out_compact(tp->net, AF_INET6, peers + i);
}
}
return 0; return 0;


bad_data: bad_data:
@@ -178,7 +191,7 @@ nc_cb(void *arg, int error, int sd)
struct http_tr_req * struct http_tr_req *
http_tr_req(struct torrent *tp, enum tr_event event, const char *aurl) http_tr_req(struct torrent *tp, enum tr_event event, const char *aurl)
{ {
char e_hash[61], e_id[61], ip_arg[INET_ADDRSTRLEN + 4], url[512], qc; char e_hash[61], e_id[61], url[512], qc;
const uint8_t *peer_id = btpd_get_peer_id(); const uint8_t *peer_id = btpd_get_peer_id();
struct http_url *http_url; struct http_url *http_url;


@@ -189,18 +202,12 @@ http_tr_req(struct torrent *tp, enum tr_event event, const char *aurl)
for (int i = 0; i < 20; i++) for (int i = 0; i < 20; i++)
snprintf(e_id + i * 3, 4, "%%%.2x", peer_id[i]); snprintf(e_id + i * 3, 4, "%%%.2x", peer_id[i]);


if (tr_ip_arg == INADDR_ANY)
ip_arg[0] = '\0';
else {
bcopy("&ip=", ip_arg, 4);
inet_ntop(AF_INET, &tr_ip_arg, ip_arg + 4, sizeof(ip_arg) - 4);
}

snprintf(url, sizeof(url), snprintf(url, sizeof(url),
"%s%cinfo_hash=%s&peer_id=%s&key=%ld%s&port=%d&uploaded=%llu" "%s%cinfo_hash=%s&peer_id=%s&key=%ld%s%s&port=%d&uploaded=%llu"
"&downloaded=%llu&left=%llu&compact=1%s%s", "&downloaded=%llu&left=%llu&compact=1%s%s",
aurl, qc, e_hash, e_id, tr_key, ip_arg, net_port, aurl, qc, e_hash, e_id, tr_key,
tp->net->uploaded, tp->net->downloaded, tr_ip_arg == NULL ? "" : "&ip=", tr_ip_arg == NULL ? "" : tr_ip_arg,
net_port, tp->net->uploaded, tp->net->downloaded,
(long long)tp->total_length - cm_content(tp), (long long)tp->total_length - cm_content(tp),
event == TR_EV_EMPTY ? "" : "&event=", m_tr_events[event]); event == TR_EV_EMPTY ? "" : "&event=", m_tr_events[event]);




+ 19
- 14
btpd/main.c Näytä tiedosto

@@ -103,6 +103,12 @@ usage(void)
"Usage: btpd [-d dir] [-p port] [more options...]\n" "Usage: btpd [-d dir] [-p port] [more options...]\n"
"\n" "\n"
"Options:\n" "Options:\n"
"-4\n"
"\tToggle use of IPv4. It's enabled by default.\n"
"\n"
"-6\n"
"\tToggle use of IPv6. It's enabled by default.\n"
"\n"
"--bw-in n\n" "--bw-in n\n"
"\tLimit incoming BitTorrent traffic to n kB/s.\n" "\tLimit incoming BitTorrent traffic to n kB/s.\n"
"\tDefault is 0 which means unlimited.\n" "\tDefault is 0 which means unlimited.\n"
@@ -121,9 +127,8 @@ usage(void)
"\tShow this text.\n" "\tShow this text.\n"
"\n" "\n"
"--ip addr\n" "--ip addr\n"
"\tMake other peers use the given address, instead of the one\n" "\tLet the tracker distribute the given address instead of the one\n"
"\tthe tracker perceives as this peer's address, when contacting\n" "\tit sees btpd connect from.\n"
"\tthis peer.\n"
"\n" "\n"
"--ipcprot mode\n" "--ipcprot mode\n"
"\tSet the protection mode of the command socket.\n" "\tSet the protection mode of the command socket.\n"
@@ -183,9 +188,15 @@ main(int argc, char **argv)
int daemonize = 1; int daemonize = 1;


for (;;) { for (;;) {
switch (getopt_long(argc, argv, "d:p:", longopts, NULL)) { switch (getopt_long(argc, argv, "46d:p:", longopts, NULL)) {
case -1: case -1:
goto args_done; goto args_done;
case '6':
net_ipv6 ^= 1;
break;
case '4':
net_ipv4 ^= 1;
break;
case 'd': case 'd':
dir = optarg; dir = optarg;
break; break;
@@ -222,16 +233,7 @@ main(int argc, char **argv)
empty_start = 1; empty_start = 1;
break; break;
case 10: case 10:
switch (inet_pton(AF_INET, optarg, &tr_ip_arg)) { tr_ip_arg = optarg;
case 1:
break;
case 0:
btpd_err("You must specify a dotted IPv4 address.\n");
break;
default:
btpd_err("inet_ntop for '%s' failed (%s).\n", optarg,
strerror(errno));
}
break; break;
default: default:
usage(); usage();
@@ -246,6 +248,9 @@ args_done:
argc -= optind; argc -= optind;
argv += optind; argv += optind;


if (!net_ipv4 && !net_ipv6)
btpd_err("You need to enable at least one ip version.\n");

if (argc > 0) if (argc > 0)
usage(); usage();




+ 1
- 1
btpd/nameconn.c Näytä tiedosto

@@ -98,7 +98,7 @@ btpd_name_connect(const char *name, short port, void (*cb)(void *, int, int),
nc->sd = -1; nc->sd = -1;
bzero(&hints, sizeof(hints)); bzero(&hints, sizeof(hints));
hints.ai_flags = AI_ADDRCONFIG; hints.ai_flags = AI_ADDRCONFIG;
hints.ai_family = AF_UNSPEC; hints.ai_family = net_af_spec();
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
nc->ai_handle = btpd_addrinfo(name, port, &hints, nc_ai_cb, nc); nc->ai_handle = btpd_addrinfo(name, port, &hints, nc_ai_cb, nc);
return nc; return nc;


+ 64
- 23
btpd/net.c Näytä tiedosto

@@ -9,7 +9,12 @@ static unsigned long m_bw_bytes_out;
static unsigned long m_rate_up; static unsigned long m_rate_up;
static unsigned long m_rate_dwn; static unsigned long m_rate_dwn;


static struct fdev m_net_incoming; struct net_listener {
int sd;
struct fdev ev;
};

static struct net_listener *m_net_listeners;


unsigned net_npeers; unsigned net_npeers;


@@ -438,9 +443,9 @@ out:
} }


int int
net_connect2(struct sockaddr *sa, socklen_t salen, int *sd) net_connect_addr(int family, struct sockaddr *sa, socklen_t salen, int *sd)
{ {
if ((*sd = socket(PF_INET, SOCK_STREAM, 0)) == -1) if ((*sd = socket(family, SOCK_STREAM, 0)) == -1)
return errno; return errno;


set_nonblocking(*sd); set_nonblocking(*sd);
@@ -456,7 +461,7 @@ net_connect2(struct sockaddr *sa, socklen_t salen, int *sd)
} }


int int
net_connect(const char *ip, int port, int *sd) net_connect_name(const char *ip, int port, int *sd)
{ {
struct addrinfo hints, *res; struct addrinfo hints, *res;
char portstr[6]; char portstr[6];
@@ -466,13 +471,14 @@ net_connect(const char *ip, int port, int *sd)
if (snprintf(portstr, sizeof(portstr), "%d", port) >= sizeof(portstr)) if (snprintf(portstr, sizeof(portstr), "%d", port) >= sizeof(portstr))
return EINVAL; return EINVAL;
bzero(&hints, sizeof(hints)); bzero(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC; hints.ai_family = net_af_spec();
hints.ai_flags = AI_NUMERICHOST; hints.ai_flags = AI_NUMERICHOST;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(ip, portstr, &hints, &res) != 0) if (getaddrinfo(ip, portstr, &hints, &res) != 0)
return errno; return errno;


int error = net_connect2(res->ai_addr, res->ai_addrlen, sd); int error =
net_connect_addr(res->ai_family, res->ai_addr, res->ai_addrlen, sd);
freeaddrinfo(res); freeaddrinfo(res);
return error; return error;
} }
@@ -487,7 +493,7 @@ net_connection_cb(int sd, short type, void *arg)
if (errno == EWOULDBLOCK || errno == ECONNABORTED) if (errno == EWOULDBLOCK || errno == ECONNABORTED)
return; return;
else else
btpd_err("accept4: %s\n", strerror(errno)); btpd_err("accept: %s\n", strerror(errno));
} }


if (set_nonblocking(nsd) != 0) { if (set_nonblocking(nsd) != 0) {
@@ -651,6 +657,17 @@ net_io_cb(int sd, short type, void *arg)
} }
} }


int
net_af_spec(void)
{
if (net_ipv4 && net_ipv6)
return AF_UNSPEC;
else if (net_ipv4)
return AF_INET;
else
return AF_INET6;
}

void void
net_init(void) net_init(void)
{ {
@@ -661,20 +678,44 @@ net_init(void)
if (net_max_peers == 0 || net_max_peers > safe_fds) if (net_max_peers == 0 || net_max_peers > safe_fds)
net_max_peers = safe_fds; net_max_peers = safe_fds;


int sd; int count = 0, flag = 1, found_ipv4 = 0, found_ipv6 = 0, sd;
int flag = 1; char portstr[6];
struct sockaddr_in addr; struct addrinfo hints, *res, *ai;
addr.sin_family = AF_INET; bzero(&hints, sizeof(hints));
addr.sin_addr.s_addr = htonl(INADDR_ANY); hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE | AI_NUMERICSERV;
addr.sin_port = htons(net_port); hints.ai_family = net_af_spec();

hints.ai_socktype = SOCK_STREAM;
if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) snprintf(portstr, sizeof(portstr), "%hd", net_port);
btpd_err("socket: %s\n", strerror(errno)); if ((errno = getaddrinfo(NULL, portstr, &hints, &res)) != 0)
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); btpd_err("getaddrinfo failed (%s).\n", gai_strerror(errno));
if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) == -1) for (ai = res; ai != NULL; ai = ai->ai_next) {
btpd_err("bind: %s\n", strerror(errno)); count++;
listen(sd, 10); if (ai->ai_family == AF_INET)
set_nonblocking(sd); found_ipv4 = 1;

else
btpd_ev_new(&m_net_incoming, sd, EV_READ, net_connection_cb, NULL); found_ipv6 = 1;
}
net_ipv4 = found_ipv4;
net_ipv6 = found_ipv6;
if (!net_ipv4 && !net_ipv6)
btpd_err("no usable address found. wrong use of -4/-6 perhaps.\n");
m_net_listeners = btpd_calloc(count, sizeof(*m_net_listeners));
for (ai = res; ai != NULL; ai = ai->ai_next) {
count--;
if ((sd = socket(ai->ai_family, ai->ai_socktype, 0)) == -1)
btpd_err("failed to create socket (%s).\n", strerror(errno));
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
#ifdef IPV6_V6ONLY
if (ai->ai_family == AF_INET6)
setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag));
#endif
if (bind(sd, ai->ai_addr, ai->ai_addrlen) == -1)
btpd_err("bind failed (%s).\n", strerror(errno));
listen(sd, 10);
set_nonblocking(sd);
m_net_listeners[count].sd = sd;
btpd_ev_new(&m_net_listeners[count].ev, sd, EV_READ,
net_connection_cb, NULL);
}
freeaddrinfo(res);
} }

+ 5
- 2
btpd/net.h Näytä tiedosto

@@ -33,7 +33,10 @@ int net_torrent_has_peer(struct net *n, const uint8_t *id);


void net_io_cb(int sd, short type, void *arg); void net_io_cb(int sd, short type, void *arg);


int net_connect2(struct sockaddr *sa, socklen_t salen, int *sd); int net_connect_addr(int family, struct sockaddr *sa, socklen_t salen,
int net_connect(const char *ip, int port, int *sd); int *sd);
int net_connect_name(const char *ip, int port, int *sd);

int net_af_spec(void);


#endif #endif

+ 3
- 1
btpd/opts.c Näytä tiedosto

@@ -14,4 +14,6 @@ int net_port = 6881;
off_t cm_alloc_size = 2048 * 1024; off_t cm_alloc_size = 2048 * 1024;
int ipcprot = 0600; int ipcprot = 0600;
int empty_start = 0; int empty_start = 0;
uint32_t tr_ip_arg = INADDR_ANY; const char *tr_ip_arg;
int net_ipv4 = 1;
int net_ipv6 = 1;

+ 2
- 1
btpd/opts.h Näytä tiedosto

@@ -11,6 +11,7 @@ extern int net_port;
extern off_t cm_alloc_size; extern off_t cm_alloc_size;
extern int ipcprot; extern int ipcprot;
extern int empty_start; extern int empty_start;
extern uint32_t tr_ip_arg; extern const char *tr_ip_arg;
extern int net_ipv4, net_ipv6;


#endif #endif

+ 28
- 9
btpd/peer.c Näytä tiedosto

@@ -295,7 +295,7 @@ peer_create_out(struct net *n, const uint8_t *id,
int sd; int sd;
struct peer *p; struct peer *p;


if (net_connect(ip, port, &sd) != 0) if (net_connect_name(ip, port, &sd) != 0)
return; return;


p = peer_create_common(sd); p = peer_create_common(sd);
@@ -304,17 +304,36 @@ peer_create_out(struct net *n, const uint8_t *id,
} }


void void
peer_create_out_compact(struct net *n, const char *compact) peer_create_out_compact(struct net *n, int family, const char *compact)
{ {
int sd; int sd;
struct peer *p; struct peer *p;
struct sockaddr_in addr; struct sockaddr_storage addr;

struct sockaddr_in *a4;
addr.sin_family = AF_INET; struct sockaddr_in6 *a6;
bcopy(compact, &addr.sin_addr.s_addr, 4); switch (family) {
bcopy(compact + 4, &addr.sin_port, 2); case AF_INET:

if (!net_ipv4)
if (net_connect2((struct sockaddr *)&addr, sizeof(addr), &sd) != 0) return;
a4 = (struct sockaddr_in *)&addr;
a4->sin_family = AF_INET;
bcopy(compact, &a4->sin_addr.s_addr, 4);
bcopy(compact + 4, &a4->sin_port, 2);
break;
case AF_INET6:
if (!net_ipv6)
return;
a6 = (struct sockaddr_in6 *)&addr;
a6->sin6_family = AF_INET6;
bcopy(compact, &a6->sin6_addr, 16);
bcopy(compact + 16, &a6->sin6_port, 2);
break;
default:
abort();
}
if (net_connect_addr(family, (struct sockaddr *)&addr,
sizeof(addr), &sd) != 0)
return; return;


p = peer_create_common(sd); p = peer_create_common(sd);


+ 1
- 1
btpd/peer.h Näytä tiedosto

@@ -35,7 +35,7 @@ int peer_requested(struct peer *p, uint32_t piece, uint32_t block);
void peer_create_in(int sd); void peer_create_in(int sd);
void peer_create_out(struct net *n, const uint8_t *id, void peer_create_out(struct net *n, const uint8_t *id,
const char *ip, int port); const char *ip, int port);
void peer_create_out_compact(struct net *n, const char *compact); void peer_create_out_compact(struct net *n, int family, const char *compact);
void peer_kill(struct peer *p); void peer_kill(struct peer *p);


void peer_on_no_reqs(struct peer *p); void peer_on_no_reqs(struct peer *p);


||||||
x
 
000:0
Loading…
Peruuta
Tallenna