Bladeren bron

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 jaren geleden
bovenliggende
commit
05329268d5
9 gewijzigde bestanden met toevoegingen van 144 en 66 verwijderingen
  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 Bestand weergeven

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

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

bad_data:
@@ -178,7 +191,7 @@ nc_cb(void *arg, int error, int sd)
struct http_tr_req *
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();
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++)
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),
"%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",
aurl, qc, e_hash, e_id, tr_key, ip_arg, net_port,
tp->net->uploaded, tp->net->downloaded,
aurl, qc, e_hash, e_id, tr_key,
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),
event == TR_EV_EMPTY ? "" : "&event=", m_tr_events[event]);



+ 19
- 14
btpd/main.c Bestand weergeven

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

for (;;) {
switch (getopt_long(argc, argv, "d:p:", longopts, NULL)) {
switch (getopt_long(argc, argv, "46d:p:", longopts, NULL)) {
case -1:
goto args_done;
case '6':
net_ipv6 ^= 1;
break;
case '4':
net_ipv4 ^= 1;
break;
case 'd':
dir = optarg;
break;
@@ -222,16 +233,7 @@ main(int argc, char **argv)
empty_start = 1;
break;
case 10:
switch (inet_pton(AF_INET, optarg, &tr_ip_arg)) {
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));
}
tr_ip_arg = optarg;
break;
default:
usage();
@@ -246,6 +248,9 @@ args_done:
argc -= optind;
argv += optind;

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

if (argc > 0)
usage();



+ 1
- 1
btpd/nameconn.c Bestand weergeven

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


+ 64
- 23
btpd/net.c Bestand weergeven

@@ -9,7 +9,12 @@ static unsigned long m_bw_bytes_out;
static unsigned long m_rate_up;
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;

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

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;

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

int
net_connect(const char *ip, int port, int *sd)
net_connect_name(const char *ip, int port, int *sd)
{
struct addrinfo hints, *res;
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))
return EINVAL;
bzero(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_family = net_af_spec();
hints.ai_flags = AI_NUMERICHOST;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(ip, portstr, &hints, &res) != 0)
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);
return error;
}
@@ -487,7 +493,7 @@ net_connection_cb(int sd, short type, void *arg)
if (errno == EWOULDBLOCK || errno == ECONNABORTED)
return;
else
btpd_err("accept4: %s\n", strerror(errno));
btpd_err("accept: %s\n", strerror(errno));
}

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

int sd;
int flag = 1;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(net_port);

if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
btpd_err("socket: %s\n", strerror(errno));
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
btpd_err("bind: %s\n", strerror(errno));
listen(sd, 10);
set_nonblocking(sd);

btpd_ev_new(&m_net_incoming, sd, EV_READ, net_connection_cb, NULL);
int count = 0, flag = 1, found_ipv4 = 0, found_ipv6 = 0, sd;
char portstr[6];
struct addrinfo hints, *res, *ai;
bzero(&hints, sizeof(hints));
hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE | AI_NUMERICSERV;
hints.ai_family = net_af_spec();
hints.ai_socktype = SOCK_STREAM;
snprintf(portstr, sizeof(portstr), "%hd", net_port);
if ((errno = getaddrinfo(NULL, portstr, &hints, &res)) != 0)
btpd_err("getaddrinfo failed (%s).\n", gai_strerror(errno));
for (ai = res; ai != NULL; ai = ai->ai_next) {
count++;
if (ai->ai_family == AF_INET)
found_ipv4 = 1;
else
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 Bestand weergeven

@@ -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);

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

int net_af_spec(void);

#endif

+ 3
- 1
btpd/opts.c Bestand weergeven

@@ -14,4 +14,6 @@ int net_port = 6881;
off_t cm_alloc_size = 2048 * 1024;
int ipcprot = 0600;
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 Bestand weergeven

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

#endif

+ 28
- 9
btpd/peer.c Bestand weergeven

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

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

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

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;
struct peer *p;
struct sockaddr_in addr;

addr.sin_family = AF_INET;
bcopy(compact, &addr.sin_addr.s_addr, 4);
bcopy(compact + 4, &addr.sin_port, 2);

if (net_connect2((struct sockaddr *)&addr, sizeof(addr), &sd) != 0)
struct sockaddr_storage addr;
struct sockaddr_in *a4;
struct sockaddr_in6 *a6;
switch (family) {
case AF_INET:
if (!net_ipv4)
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;

p = peer_create_common(sd);


+ 1
- 1
btpd/peer.h Bestand weergeven

@@ -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_out(struct net *n, const uint8_t *id,
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_on_no_reqs(struct peer *p);


Laden…
Annuleren
Opslaan