Browse Source

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 years ago
parent
commit
05329268d5
9 changed files with 144 additions and 66 deletions
  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 View File

@@ -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);
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 } 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,
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), (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 View File

@@ -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"
"\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" "\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)) {
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; 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 View File

@@ -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 View File

@@ -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 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 View File

@@ -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(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 #endif

+ 3
- 1
btpd/opts.c View File

@@ -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 View File

@@ -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 View File

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

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; return;


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


+ 1
- 1
btpd/peer.h View File

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


Loading…
Cancel
Save