Skip to content
Merged

Ipv6 #507

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AUTHORS
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Jari Sundell <jaris@ifi.uio.no>
Jari Sundell <sundell.software@gmail.com>
9 changes: 7 additions & 2 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,10 @@ DEPENDENCIES

CONTACT

Send bug reports, suggestions and patches to <jaris@ifi.uio.no> or
to the mailinglist.
Jari Sundell

Skomakerveien 33
3185 Skoppum, NORWAY

Send bug reports, suggestions and patches to
<sundell.software@gmail.com> or to the mailinglist.
165 changes: 122 additions & 43 deletions rak/socket_address.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,11 @@ class socket_address {
const sockaddr* c_sockaddr() const { return &m_sockaddr; }
const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddrInet; }

#ifdef RAK_USE_INET6
socket_address_inet6* sa_inet6() { return reinterpret_cast<socket_address_inet6*>(this); }
const socket_address_inet6* sa_inet6() const { return reinterpret_cast<const socket_address_inet6*>(this); }

sockaddr_in6* c_sockaddr_inet6() { return &m_sockaddrInet6; }
const sockaddr_in6* c_sockaddr_inet6() const { return &m_sockaddrInet6; }
#endif

// Copy a socket address which has the length 'length. Zero out any
// extranous bytes and ensure it does not go beyond the size of this
Expand All @@ -139,13 +137,11 @@ class socket_address {
union {
sockaddr m_sockaddr;
sockaddr_in m_sockaddrInet;
#ifdef RAK_USE_INET6
sockaddr_in6 m_sockaddrInet6;
#endif
};
};

// Remeber to set the AF_INET.
// Remember to set the AF_INET.

class socket_address_inet {
public:
Expand Down Expand Up @@ -184,6 +180,8 @@ class socket_address_inet {

const sockaddr* c_sockaddr() const { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddr; }

socket_address_inet6 to_mapped_address() const;

bool operator == (const socket_address_inet& rhs) const;
bool operator < (const socket_address_inet& rhs) const;
Expand All @@ -192,57 +190,56 @@ class socket_address_inet {
struct sockaddr_in m_sockaddr;
};

// Unique key for the address, excluding port numbers etc.
class socket_address_key {
class socket_address_inet6 {
public:
// socket_address_host_key() {}
bool is_any() const { return is_port_any() && is_address_any(); }
bool is_valid() const { return !is_port_any() && !is_address_any(); }
bool is_port_any() const { return port() == 0; }
bool is_address_any() const { return std::memcmp(&m_sockaddr.sin6_addr, &in6addr_any, sizeof(in6_addr)) == 0; }

socket_address_key(const socket_address& sa) {
*this = sa;
}
void clear() { std::memset(this, 0, sizeof(socket_address_inet6)); set_family(); }

socket_address_key& operator = (const socket_address& sa) {
if (sa.family() == 0) {
std::memset(this, 0, sizeof(socket_address_key));
uint16_t port() const { return ntohs(m_sockaddr.sin6_port); }
uint16_t port_n() const { return m_sockaddr.sin6_port; }
void set_port(uint16_t p) { m_sockaddr.sin6_port = htons(p); }
void set_port_n(uint16_t p) { m_sockaddr.sin6_port = p; }

} else if (sa.family() == socket_address::af_inet) {
// Using hardware order as we use operator < to compare when
// using inet only.
m_addr.s_addr = sa.sa_inet()->address_h();
in6_addr address() const { return m_sockaddr.sin6_addr; }
const in6_addr* address_ptr() const { return &m_sockaddr.sin6_addr; }
std::string address_str() const;
bool address_c_str(char* buf, socklen_t size) const;

} else {
// When we implement INET6 handling, embed the ipv4 address in
// the ipv6 address.
throw std::logic_error("socket_address_key(...) received an unsupported protocol family.");
}
void set_address(in6_addr a) { m_sockaddr.sin6_addr = a; }
bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); }
bool set_address_c_str(const char* a);

return *this;
}
void set_address_any() { set_port(0); set_address(in6addr_any); }

// socket_address_key& operator = (const socket_address_key& sa) {
// }
sa_family_t family() const { return m_sockaddr.sin6_family; }
void set_family() { m_sockaddr.sin6_family = AF_INET6; }

bool operator < (const socket_address_key& sa) const {
// Compare the memory area instead.
return m_addr.s_addr < sa.m_addr.s_addr;
}
sockaddr* c_sockaddr() { return reinterpret_cast<sockaddr*>(&m_sockaddr); }
sockaddr_in6* c_sockaddr_inet6() { return &m_sockaddr; }

const sockaddr* c_sockaddr() const { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
const sockaddr_in6* c_sockaddr_inet6() const { return &m_sockaddr; }

socket_address normalize_address() const;

bool operator == (const socket_address_inet6& rhs) const;
bool operator < (const socket_address_inet6& rhs) const;

private:
union {
in_addr m_addr;
// #ifdef RAK_USE_INET6
// in_addr6 m_addr6;
// #endif
};
struct sockaddr_in6 m_sockaddr;
};

inline bool
socket_address::is_valid() const {
switch (family()) {
case af_inet:
return sa_inet()->is_valid();
// case af_inet6:
// return sa_inet6().is_valid();
case af_inet6:
return sa_inet6()->is_valid();
default:
return false;
}
Expand All @@ -253,6 +250,8 @@ socket_address::is_bindable() const {
switch (family()) {
case af_inet:
return !sa_inet()->is_address_any();
case af_inet6:
return !sa_inet6()->is_address_any();
default:
return false;
}
Expand All @@ -263,6 +262,8 @@ socket_address::is_address_any() const {
switch (family()) {
case af_inet:
return sa_inet()->is_address_any();
case af_inet6:
return sa_inet6()->is_address_any();
default:
return true;
}
Expand All @@ -273,6 +274,8 @@ socket_address::port() const {
switch (family()) {
case af_inet:
return sa_inet()->port();
case af_inet6:
return sa_inet6()->port();
default:
return 0;
}
Expand All @@ -283,6 +286,8 @@ socket_address::set_port(uint16_t p) {
switch (family()) {
case af_inet:
return sa_inet()->set_port(p);
case af_inet6:
return sa_inet6()->set_port(p);
default:
break;
}
Expand All @@ -293,6 +298,8 @@ socket_address::address_str() const {
switch (family()) {
case af_inet:
return sa_inet()->address_str();
case af_inet6:
return sa_inet6()->address_str();
default:
return std::string();
}
Expand All @@ -303,6 +310,8 @@ socket_address::address_c_str(char* buf, socklen_t size) const {
switch (family()) {
case af_inet:
return sa_inet()->address_c_str(buf, size);
case af_inet6:
return sa_inet6()->address_c_str(buf, size);
default:
return false;
}
Expand All @@ -314,6 +323,10 @@ socket_address::set_address_c_str(const char* a) {
sa_inet()->set_family();
return true;

} else if (sa_inet6()->set_address_c_str(a)) {
sa_inet6()->set_family();
return true;

} else {
return false;
}
Expand All @@ -325,6 +338,8 @@ socket_address::length() const {
switch(family()) {
case af_inet:
return sizeof(sockaddr_in);
case af_inet6:
return sizeof(sockaddr_in6);
default:
return 0;
}
Expand All @@ -349,8 +364,8 @@ socket_address::operator == (const socket_address& rhs) const {
switch (family()) {
case af_inet:
return *sa_inet() == *rhs.sa_inet();
// case af_inet6:
// return *sa_inet6() == *rhs.sa_inet6();
case af_inet6:
return *sa_inet6() == *rhs.sa_inet6();
default:
throw std::logic_error("socket_address::operator == (rhs) invalid type comparison.");
}
Expand All @@ -364,8 +379,8 @@ socket_address::operator < (const socket_address& rhs) const {
switch (family()) {
case af_inet:
return *sa_inet() < *rhs.sa_inet();
// case af_inet6:
// return *sa_inet6() < *rhs.sa_inet6();
case af_inet6:
return *sa_inet6() < *rhs.sa_inet6();
default:
throw std::logic_error("socket_address::operator < (rhs) invalid type comparison.");
}
Expand All @@ -391,6 +406,21 @@ socket_address_inet::set_address_c_str(const char* a) {
return inet_pton(AF_INET, a, &m_sockaddr.sin_addr);
}

inline socket_address_inet6
socket_address_inet::to_mapped_address() const {
uint32_t addr32[4];
addr32[0] = 0;
addr32[1] = 0;
addr32[2] = htonl(0xffff);
addr32[3] = m_sockaddr.sin_addr.s_addr;

socket_address_inet6 sa;
sa.clear();
sa.set_address(*reinterpret_cast<in6_addr *>(addr32));
sa.set_port_n(m_sockaddr.sin_port);
return sa;
}

inline bool
socket_address_inet::operator == (const socket_address_inet& rhs) const {
return
Expand All @@ -406,6 +436,55 @@ socket_address_inet::operator < (const socket_address_inet& rhs) const {
m_sockaddr.sin_port < rhs.m_sockaddr.sin_port);
}

inline std::string
socket_address_inet6::address_str() const {
char buf[INET6_ADDRSTRLEN];

if (!address_c_str(buf, INET6_ADDRSTRLEN))
return std::string();

return std::string(buf);
}

inline bool
socket_address_inet6::address_c_str(char* buf, socklen_t size) const {
return inet_ntop(family(), &m_sockaddr.sin6_addr, buf, size);
}

inline bool
socket_address_inet6::set_address_c_str(const char* a) {
return inet_pton(AF_INET6, a, &m_sockaddr.sin6_addr);
}

inline socket_address
socket_address_inet6::normalize_address() const {
const uint32_t *addr32 = reinterpret_cast<const uint32_t *>(m_sockaddr.sin6_addr.s6_addr);
if (addr32[0] == 0 && addr32[1] == 0 && addr32[2] == htonl(0xffff)) {
socket_address addr4;
addr4.sa_inet()->set_family();
addr4.sa_inet()->set_address_n(addr32[3]);
addr4.sa_inet()->set_port_n(m_sockaddr.sin6_port);
return addr4;
}
return *reinterpret_cast<const socket_address*>(this);
}

inline bool
socket_address_inet6::operator == (const socket_address_inet6& rhs) const {
return
memcmp(&m_sockaddr.sin6_addr, &rhs.m_sockaddr.sin6_addr, sizeof(in6_addr)) == 0 &&
m_sockaddr.sin6_port == rhs.m_sockaddr.sin6_port;
}

inline bool
socket_address_inet6::operator < (const socket_address_inet6& rhs) const {
int addr_comp = memcmp(&m_sockaddr.sin6_addr, &rhs.m_sockaddr.sin6_addr, sizeof(in6_addr));
return
addr_comp < 0 ||
(addr_comp == 0 ||
m_sockaddr.sin6_port < rhs.m_sockaddr.sin6_port);
}

}

#endif
7 changes: 5 additions & 2 deletions src/command_download.cc
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,10 @@ apply_d_add_peer(core::Download* download, const std::string& arg) {
if (download->download()->info()->is_private())
throw torrent::input_error("Download is private.");

ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy);
ret = std::sscanf(arg.c_str(), "[%64[^]]]:%i%c", host, &port, &dummy);

if (ret < 1)
ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy);

if (ret == 1)
port = 6881;
Expand All @@ -318,7 +321,7 @@ apply_d_add_peer(core::Download* download, const std::string& arg) {
if (port < 1 || port > 65535)
throw torrent::input_error("Invalid port number.");

torrent::connection_manager()->resolver()(host, (int)rak::socket_address::pf_inet, SOCK_STREAM, call_add_d_peer_t(download, port));
torrent::connection_manager()->resolver()(host, (int)rak::socket_address::pf_unspec, SOCK_STREAM, call_add_d_peer_t(download, port));
}

torrent::Object
Expand Down
5 changes: 3 additions & 2 deletions src/command_network.cc
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,9 @@ apply_scgi(const std::string& arg, int type) {
lt_log_print(torrent::LOG_RPC_EVENTS,
"The SCGI socket has not been bound to any address and likely poses a security risk.");

} else if (std::sscanf(arg.c_str(), "%1023[^:]:%i%c", address, &port, &dummy) == 2) {
if ((err = rak::address_info::get_address_info(address, PF_INET, SOCK_STREAM, &ai)) != 0)
} else if (std::sscanf(arg.c_str(), "%1023[^:]:%i%c", address, &port, &dummy) == 2 ||
std::sscanf(arg.c_str(), "[%64[^]]]:%i%c", address, &port, &dummy) == 2) { // [xx::xx]:port format
if ((err = rak::address_info::get_address_info(address,PF_UNSPEC, SOCK_STREAM, &ai)) != 0)
throw torrent::input_error("Could not bind address: " + std::string(rak::address_info::strerror(err)) + ".");

saPtr = ai->address();
Expand Down
7 changes: 6 additions & 1 deletion src/command_peer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,12 @@ retrieve_p_id_html(torrent::Peer* peer) {

torrent::Object
retrieve_p_address(torrent::Peer* peer) {
return rak::socket_address::cast_from(peer->peer_info()->socket_address())->address_str();
const rak::socket_address *addr = rak::socket_address::cast_from(peer->peer_info()->socket_address());

if (addr->family() == rak::socket_address::af_inet6)
return "[" + addr->address_str() + "]";
else
return addr->address_str();
}

torrent::Object
Expand Down
17 changes: 16 additions & 1 deletion src/core/curl_get.cc
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,13 @@ CurlGet::start() {
curl_easy_setopt(m_handle, CURLOPT_NOSIGNAL, (long)1);
curl_easy_setopt(m_handle, CURLOPT_FOLLOWLOCATION, (long)1);
curl_easy_setopt(m_handle, CURLOPT_MAXREDIRS, (long)5);
curl_easy_setopt(m_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);

curl_easy_setopt(m_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);

curl_easy_setopt(m_handle, CURLOPT_ENCODING, "");

m_ipv6 = false;

m_stack->add_get(this);
}

Expand All @@ -110,6 +114,17 @@ CurlGet::close() {
m_handle = NULL;
}

void
CurlGet::retry_ipv6() {
CURL* nhandle = curl_easy_duphandle(m_handle);

curl_easy_setopt(nhandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
curl_easy_cleanup(m_handle);

m_handle = nhandle;
m_ipv6 = true;
}

void
CurlGet::receive_timeout() {
return m_stack->transfer_done(m_handle, "Timed out");
Expand Down
Loading