Bug 797262 - IPV6 support for webrtc. r=drno

This commit is contained in:
Byron Campen [:bwc] 2015-04-22 15:02:50 -05:00
parent a7fb589b65
commit 4965ecc09e
46 changed files with 1064 additions and 792 deletions

View File

@ -119,7 +119,7 @@ GetInterfaces(std::vector<NetworkInterface>* aInterfaces)
int
nr_stun_get_addrs(nr_local_addr aAddrs[], int aMaxAddrs,
int aDropLoopback, int* aCount)
int aDropLoopback, int aDropLinkLocal, int* aCount)
{
nsresult rv;
int r;
@ -141,7 +141,6 @@ nr_stun_get_addrs(nr_local_addr aAddrs[], int aMaxAddrs,
for (size_t i = 0; i < num_interface; ++i) {
NetworkInterface &interface = interfaces[i];
if (nr_sockaddr_to_transport_addr((sockaddr*)&(interface.addr),
sizeof(struct sockaddr_in),
IPPROTO_UDP, 0, &(aAddrs[n].addr))) {
r_log(NR_LOG_STUN, LOG_WARNING, "Problem transforming address");
return R_FAILED;
@ -154,7 +153,7 @@ nr_stun_get_addrs(nr_local_addr aAddrs[], int aMaxAddrs,
}
*aCount = n;
r = nr_stun_remove_duplicate_addrs(aAddrs, aDropLoopback, aCount);
r = nr_stun_remove_duplicate_addrs(aAddrs, aDropLoopback, aDropLinkLocal, aCount);
if (r != 0) {
return r;
}

View File

@ -337,20 +337,11 @@ static int nr_transport_addr_to_praddr(nr_transport_addr *addr,
naddr->inet.ip = addr->u.addr4.sin_addr.s_addr;
break;
case NR_IPV6:
#if 0
naddr->ipv6.family = PR_AF_INET6;
naddr->ipv6.port = addr->u.addr6.sin6_port;
#ifdef LINUX
memcpy(naddr->ipv6.ip._S6_un._S6_u8,
&addr->u.addr6.sin6_addr.__in6_u.__u6_addr8, 16);
#else
memcpy(naddr->ipv6.ip._S6_un._S6_u8,
&addr->u.addr6.sin6_addr.__u6_addr.__u6_addr8, 16);
#endif
#else
// TODO: make IPv6 work
ABORT(R_INTERNAL);
#endif
naddr->ipv6.flowinfo = addr->u.addr6.sin6_flowinfo;
memcpy(&naddr->ipv6.ip, &addr->u.addr6.sin6_addr, sizeof(in6_addr));
naddr->ipv6.scope_id = addr->u.addr6.sin6_scope_id;
break;
default:
ABORT(R_BAD_ARGS);
@ -440,6 +431,7 @@ int nr_praddr_to_transport_addr(const PRNetAddr *praddr,
int _status;
int r;
struct sockaddr_in ip4;
struct sockaddr_in6 ip6;
switch(praddr->raw.family) {
case PR_AF_INET:
@ -447,18 +439,19 @@ int nr_praddr_to_transport_addr(const PRNetAddr *praddr,
ip4.sin_addr.s_addr = praddr->inet.ip;
ip4.sin_port = praddr->inet.port;
if ((r = nr_sockaddr_to_transport_addr((sockaddr *)&ip4,
sizeof(ip4),
protocol, keep,
addr)))
ABORT(r);
break;
case PR_AF_INET6:
#if 0
r = nr_sockaddr_to_transport_addr((sockaddr *)&praddr->raw,
sizeof(struct sockaddr_in6),IPPROTO_UDP,keep,addr);
ip6.sin6_family = PF_INET6;
ip6.sin6_port = praddr->ipv6.port;
ip6.sin6_flowinfo = praddr->ipv6.flowinfo;
memcpy(&ip6.sin6_addr, &praddr->ipv6.ip, sizeof(in6_addr));
ip6.sin6_scope_id = praddr->ipv6.scope_id;
if ((r = nr_sockaddr_to_transport_addr((sockaddr *)&ip6,protocol,keep,addr)))
ABORT(r);
break;
#endif
ABORT(R_BAD_ARGS);
default:
MOZ_ASSERT(false);
ABORT(R_BAD_ARGS);
@ -516,14 +509,16 @@ int NrSocket::create(nr_transport_addr *addr) {
switch (addr->protocol) {
case IPPROTO_UDP:
if (!(fd_ = PR_NewUDPSocket())) {
r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create socket");
if (!(fd_ = PR_OpenUDPSocket(naddr.raw.family))) {
r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create UDP socket, "
"family=%d, err=%d", naddr.raw.family, PR_GetError());
ABORT(R_INTERNAL);
}
break;
case IPPROTO_TCP:
if (!(fd_ = PR_NewTCPSocket())) {
r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create socket");
if (!(fd_ = PR_OpenTCPSocket(naddr.raw.family))) {
r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create TCP socket, "
"family=%d, err=%d", naddr.raw.family, PR_GetError());
ABORT(R_INTERNAL);
}
// Set ReuseAddr for TCP sockets to enable having several
@ -686,7 +681,8 @@ int NrSocket::sendto(const void *msg, size_t len,
if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
ABORT(R_WOULDBLOCK);
r_log(LOG_GENERIC, LOG_INFO, "Error in sendto: %s", to->as_string);
r_log(LOG_GENERIC, LOG_INFO, "Error in sendto %s: %d",
to->as_string, PR_GetError());
ABORT(R_IO_ERROR);
}

View File

@ -380,7 +380,8 @@ RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name,
bool offerer,
bool set_interface_priorities,
bool allow_loopback,
bool tcp_enabled) {
bool tcp_enabled,
bool allow_link_local) {
RefPtr<NrIceCtx> ctx = new NrIceCtx(name, offerer);
@ -472,6 +473,10 @@ RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name,
if (allow_loopback) {
NR_reg_set_char((char *)NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, 1);
}
if (allow_link_local) {
NR_reg_set_char((char *)NR_STUN_REG_PREF_ALLOW_LINK_LOCAL_ADDRS, 1);
}
}
// Create the ICE context

View File

@ -212,7 +212,8 @@ class NrIceCtx {
bool offerer,
bool set_interface_priorities = true,
bool allow_loopback = false,
bool tcp_enabled = true);
bool tcp_enabled = true,
bool allow_link_local = false);
// Deinitialize all ICE global state. Used only for testing.
static void internal_DeinitializeGlobal();

View File

@ -150,6 +150,7 @@ int NrIceResolver::resolve(nr_resolver_resource *resource,
MOZ_ASSERT(allocated_resolvers_ > 0);
ASSERT_ON_THREAD(sts_thread_);
nsRefPtr<PendingResolution> pr;
uint32_t resolve_flags = 0;
if (resource->transport_protocol != IPPROTO_UDP &&
resource->transport_protocol != IPPROTO_TCP) {
@ -162,8 +163,20 @@ int NrIceResolver::resolve(nr_resolver_resource *resource,
resource->transport_protocol :
IPPROTO_UDP,
cb, cb_arg);
switch(resource->address_family) {
case AF_INET:
resolve_flags |= nsIDNSService::RESOLVE_DISABLE_IPV6;
break;
case AF_INET6:
resolve_flags |= nsIDNSService::RESOLVE_DISABLE_IPV4;
break;
default:
ABORT(R_BAD_ARGS);
}
if (NS_FAILED(dns_->AsyncResolve(nsAutoCString(resource->domain_name),
nsIDNSService::RESOLVE_DISABLE_IPV6, pr,
resolve_flags, pr,
sts_thread_, getter_AddRefs(pr->request_)))) {
MOZ_MTLOG(ML_ERROR, "AsyncResolve failed.");
ABORT(R_NOT_FOUND);

View File

@ -122,6 +122,7 @@ int NrIceResolverFake::resolve(void *obj,
resource->transport_protocol ?
resource->transport_protocol :
IPPROTO_UDP,
resource->address_family,
cb, cb_arg);
if ((r=NR_ASYNC_TIMER_SET(fake->delay_ms_,NrIceResolverFake::resolve_cb,
@ -140,7 +141,8 @@ void NrIceResolverFake::resolve_cb(NR_SOCKET s, int how, void *cb_arg) {
MOZ_ASSERT(cb_arg);
PendingResolution *pending = static_cast<PendingResolution *>(cb_arg);
const PRNetAddr *addr=pending->resolver_->Resolve(pending->hostname_);
const PRNetAddr *addr=pending->resolver_->Resolve(pending->hostname_,
pending->address_family_);
if (addr) {
nr_transport_addr transport_addr;

View File

@ -63,7 +63,16 @@ class NrIceResolverFake {
~NrIceResolverFake();
void SetAddr(const std::string& hostname, const PRNetAddr& addr) {
addrs_[hostname] = addr;
switch (addr.raw.family) {
case AF_INET:
addrs_[hostname] = addr;
break;
case AF_INET6:
addrs6_[hostname] = addr;
break;
default:
MOZ_CRASH();
}
}
nr_resolver *AllocateResolver();
@ -83,11 +92,21 @@ private:
static int cancel(void *obj, void *handle);
// Get an address.
const PRNetAddr *Resolve(const std::string& hostname) {
if (!addrs_.count(hostname))
return nullptr;
const PRNetAddr *Resolve(const std::string& hostname, int address_family) {
switch (address_family) {
case AF_INET:
if (!addrs_.count(hostname))
return nullptr;
return &addrs_[hostname];
return &addrs_[hostname];
case AF_INET6:
if (!addrs6_.count(hostname))
return nullptr;
return &addrs6_[hostname];
default:
MOZ_CRASH();
}
}
@ -96,18 +115,21 @@ private:
const std::string& hostname,
uint16_t port,
int transport,
int address_family,
int (*cb)(void *cb_arg, nr_transport_addr *addr),
void *cb_arg) :
resolver_(resolver),
hostname_(hostname),
port_(port),
transport_(transport),
address_family_(address_family),
cb_(cb), cb_arg_(cb_arg) {}
NrIceResolverFake *resolver_;
std::string hostname_;
uint16_t port_;
int transport_;
int address_family_;
int (*cb_)(void *cb_arg, nr_transport_addr *addr);
void *cb_arg_;
void *timer_handle_;
@ -115,6 +137,7 @@ private:
nr_resolver_vtbl* vtbl_;
std::map<std::string, PRNetAddr> addrs_;
std::map<std::string, PRNetAddr> addrs6_;
uint32_t delay_ms_;
int allocated_resolvers_;
};

View File

@ -18,7 +18,8 @@ public:
: key_(),
is_vpn_(-1),
estimated_speed_(-1),
type_preference_(-1) {}
type_preference_(-1),
ip_version_(-1) {}
bool Init(const nr_local_addr& local_addr) {
char buf[MAXIFNAME + 41];
@ -31,6 +32,7 @@ public:
is_vpn_ = (local_addr.interface.type & NR_INTERFACE_TYPE_VPN) != 0 ? 1 : 0;
estimated_speed_ = local_addr.interface.estimated_speed;
type_preference_ = GetNetworkTypePreference(local_addr.interface.type);
ip_version_ = local_addr.addr.ip_version;
return true;
}
@ -54,6 +56,11 @@ public:
return estimated_speed_ > rhs.estimated_speed_;
}
// Prefer IPV6 over IPV4
if (ip_version_ != rhs.ip_version_) {
return ip_version_ > rhs.ip_version_;
}
// All things above are the same, we can at least sort with key.
return key_ < rhs.key_;
}
@ -82,6 +89,7 @@ private:
int is_vpn_;
int estimated_speed_;
int type_preference_;
int ip_version_;
};
class InterfacePrioritizer {

View File

@ -21,42 +21,51 @@ extern "C" {
namespace {
class NetAddressAdapter {
class NetAddrCompare {
public:
MOZ_IMPLICIT NetAddressAdapter(const mozilla::net::NetAddr& netaddr)
: addr_(ntohl(netaddr.inet.ip)),
port_(ntohs(netaddr.inet.port)) {
MOZ_ASSERT(netaddr.raw.family == AF_INET);
}
bool operator()(const mozilla::net::NetAddr& lhs,
const mozilla::net::NetAddr& rhs) const {
if (lhs.raw.family != rhs.raw.family) {
return lhs.raw.family < rhs.raw.family;
}
bool operator<(const NetAddressAdapter& rhs) const {
return addr_ != rhs.addr_ ? (addr_ < rhs.addr_) : (port_ < rhs.port_);
}
bool operator!=(const NetAddressAdapter& rhs) const {
return (*this < rhs) || (rhs < *this);
}
private:
const uint32_t addr_;
const uint16_t port_;
switch (lhs.raw.family) {
case AF_INET:
if (lhs.inet.port != rhs.inet.port) {
return lhs.inet.port < rhs.inet.port;
}
return lhs.inet.ip < rhs.inet.ip;
case AF_INET6:
if (lhs.inet6.port != rhs.inet6.port) {
return lhs.inet6.port < rhs.inet6.port;
}
return memcmp(&lhs.inet6.ip, &rhs.inet6.ip, sizeof(lhs.inet6.ip)) < 0;
default:
MOZ_ASSERT(false);
}
return false;
}
};
class PendingSTUNRequest {
public:
PendingSTUNRequest(const NetAddressAdapter& netaddr, const UINT12 &id)
PendingSTUNRequest(const mozilla::net::NetAddr& netaddr, const UINT12 &id)
: id_(id),
net_addr_(netaddr),
is_id_set_(true) {}
MOZ_IMPLICIT PendingSTUNRequest(const NetAddressAdapter& netaddr)
MOZ_IMPLICIT PendingSTUNRequest(const mozilla::net::NetAddr& netaddr)
: id_(),
net_addr_(netaddr),
is_id_set_(false) {}
bool operator<(const PendingSTUNRequest& rhs) const {
if (net_addr_ != rhs.net_addr_) {
return net_addr_ < rhs.net_addr_;
if (NetAddrCompare()(net_addr_, rhs.net_addr_)) {
return true;
}
if (NetAddrCompare()(rhs.net_addr_, net_addr_)) {
return false;
}
if (!is_id_set_ && !rhs.is_id_set_) {
@ -76,7 +85,7 @@ class PendingSTUNRequest {
private:
const UINT12 id_;
const NetAddressAdapter net_addr_;
const mozilla::net::NetAddr net_addr_;
const bool is_id_set_;
};
@ -101,7 +110,7 @@ class STUNUDPSocketFilter : public nsIUDPSocketFilter {
const uint8_t *data,
uint32_t len);
std::set<NetAddressAdapter> white_list_;
std::set<mozilla::net::NetAddr, NetAddrCompare> white_list_;
std::set<PendingSTUNRequest> pending_requests_;
std::set<PendingSTUNRequest> response_allowed_;
};
@ -114,12 +123,6 @@ STUNUDPSocketFilter::FilterPacket(const mozilla::net::NetAddr *remote_addr,
uint32_t len,
int32_t direction,
bool *result) {
// Allowing IPv4 address only.
if (remote_addr->raw.family != AF_INET) {
*result = false;
return NS_OK;
}
switch (direction) {
case nsIUDPSocketFilter::SF_INCOMING:
*result = filter_incoming_packet(remote_addr, data, len);

View File

@ -64,7 +64,7 @@ class BufferedStunSocketTest : public ::testing::Test {
ASSERT_EQ(0, r);
dummy_ = dummy.forget(); // Now owned by test_socket_.
r = nr_ip4_str_port_to_transport_addr(
r = nr_str_port_to_transport_addr(
(char *)"192.0.2.133", 3333, IPPROTO_TCP, &remote_addr_);
ASSERT_EQ(0, r);
@ -184,7 +184,7 @@ TEST_F(BufferedStunSocketTest, TestSendToReject) {
TEST_F(BufferedStunSocketTest, TestSendToWrongAddr) {
nr_transport_addr addr;
int r = nr_ip4_str_port_to_transport_addr(
int r = nr_str_port_to_transport_addr(
(char *)"192.0.2.134", 3333, IPPROTO_TCP, &addr);
ASSERT_EQ(0, r);

View File

@ -354,8 +354,8 @@ class IceTestPeer : public sigslot::has_slots<> {
}
void UseTestStunServer() {
SetStunServer(TestStunServer::GetInstance()->addr(),
TestStunServer::GetInstance()->port());
SetStunServer(TestStunServer::GetInstance(AF_INET)->addr(),
TestStunServer::GetInstance(AF_INET)->port());
}
void SetTurnServer(const std::string addr, uint16_t port,
@ -382,15 +382,15 @@ class IceTestPeer : public sigslot::has_slots<> {
ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetTurnServers(servers)));
}
void SetFakeResolver() {
void SetFakeResolver(const std::string& ip = g_stun_server_address,
const std::string& fqdn = g_stun_server_hostname) {
ASSERT_TRUE(NS_SUCCEEDED(dns_resolver_->Init()));
if (!g_stun_server_address.empty() && !g_stun_server_hostname.empty()) {
if (!ip.empty() && !fqdn.empty()) {
PRNetAddr addr;
PRStatus status = PR_StringToNetAddr(g_stun_server_address.c_str(),
&addr);
PRStatus status = PR_StringToNetAddr(ip.c_str(), &addr);
addr.inet.port = kDefaultStunServerPort;
ASSERT_EQ(PR_SUCCESS, status);
fake_resolver_.SetAddr(g_stun_server_hostname, addr);
fake_resolver_.SetAddr(fqdn, addr);
}
ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetResolver(
fake_resolver_.AllocateResolver())));
@ -1098,9 +1098,16 @@ void SchedulableTrickleCandidate::Trickle() {
class IceGatherTest : public ::testing::Test {
public:
void SetUp() {
test_utils->sts_target()->Dispatch(WrapRunnable(TestStunServer::GetInstance(),
&TestStunServer::Reset),
NS_DISPATCH_SYNC);
test_utils->sts_target()->Dispatch(
WrapRunnable(TestStunServer::GetInstance(AF_INET),
&TestStunServer::Reset),
NS_DISPATCH_SYNC);
if (TestStunServer::GetInstance(AF_INET6)) {
test_utils->sts_target()->Dispatch(
WrapRunnable(TestStunServer::GetInstance(AF_INET6),
&TestStunServer::Reset),
NS_DISPATCH_SYNC);
}
}
void TearDown() {
@ -1135,54 +1142,90 @@ class IceGatherTest : public ::testing::Test {
ASSERT_TRUE_WAIT(peer_->gathering_complete(), waitTime);
}
void UseFakeStunUdpServerWithResponse(const std::string& fake_addr,
uint16_t fake_port) {
EnsurePeer();
TestStunServer::GetInstance()->SetResponseAddr(fake_addr, fake_port);
// Sets an additional stun server
peer_->SetStunServer(TestStunServer::GetInstance()->addr(),
TestStunServer::GetInstance()->port(),
kNrIceTransportUdp);
void AddStunServerWithResponse(
const std::string& fake_addr,
uint16_t fake_port,
const std::string& fqdn,
const std::string& proto,
std::vector<NrIceStunServer>* stun_servers) {
int family;
if (fake_addr.find(':') != std::string::npos) {
family = AF_INET6;
} else {
family = AF_INET;
}
std::string stun_addr;
uint16_t stun_port;
if (proto == kNrIceTransportUdp) {
TestStunServer::GetInstance(family)->SetResponseAddr(fake_addr,
fake_port);
stun_addr = TestStunServer::GetInstance(family)->addr();
stun_port = TestStunServer::GetInstance(family)->port();
} else if (proto == kNrIceTransportTcp) {
TestStunTcpServer::GetInstance(family)->SetResponseAddr(fake_addr,
fake_port);
stun_addr = TestStunTcpServer::GetInstance(family)->addr();
stun_port = TestStunTcpServer::GetInstance(family)->port();
} else {
MOZ_CRASH();
}
if (!fqdn.empty()) {
peer_->SetFakeResolver(stun_addr, fqdn);
stun_addr = fqdn;
}
stun_servers->push_back(*NrIceStunServer::Create(stun_addr,
stun_port,
proto.c_str()));
}
void UseFakeStunTcpServerWithResponse(const std::string& fake_addr,
uint16_t fake_port) {
EnsurePeer();
TestStunTcpServer::GetInstance()->SetResponseAddr(fake_addr, fake_port);
// Sets an additional stun server
peer_->SetStunServer(TestStunTcpServer::GetInstance()->addr(),
TestStunTcpServer::GetInstance()->port(),
kNrIceTransportTcp);
}
void UseFakeStunUdpTcpServersWithResponse(const std::string& fake_udp_addr,
uint16_t fake_udp_port,
const std::string& fake_tcp_addr,
uint16_t fake_tcp_port) {
void UseFakeStunUdpServerWithResponse(
const std::string& fake_addr,
uint16_t fake_port,
const std::string& fqdn = std::string()) {
EnsurePeer();
std::vector<NrIceStunServer> stun_servers;
AddStunServerWithResponse(fake_addr, fake_port, fqdn, "udp", &stun_servers);
peer_->SetStunServers(stun_servers);
}
stun_servers.push_back(*NrIceStunServer::Create(
TestStunServer::GetInstance()->addr(),
TestStunServer::GetInstance()->port(),
kNrIceTransportUdp));
stun_servers.push_back(*NrIceStunServer::Create(
TestStunTcpServer::GetInstance()->addr(),
TestStunTcpServer::GetInstance()->port(),
kNrIceTransportTcp));
void UseFakeStunTcpServerWithResponse(
const std::string& fake_addr,
uint16_t fake_port,
const std::string& fqdn = std::string()) {
EnsurePeer();
std::vector<NrIceStunServer> stun_servers;
AddStunServerWithResponse(fake_addr, fake_port, fqdn, "tcp", &stun_servers);
peer_->SetStunServers(stun_servers);
}
void UseFakeStunUdpTcpServersWithResponse(
const std::string& fake_udp_addr,
uint16_t fake_udp_port,
const std::string& fake_tcp_addr,
uint16_t fake_tcp_port) {
EnsurePeer();
std::vector<NrIceStunServer> stun_servers;
AddStunServerWithResponse(fake_udp_addr,
fake_udp_port,
"", // no fqdn
"udp",
&stun_servers);
AddStunServerWithResponse(fake_tcp_addr,
fake_tcp_port,
"", // no fqdn
"tcp",
&stun_servers);
TestStunServer::GetInstance()->SetResponseAddr(fake_udp_addr,
fake_udp_port);
TestStunTcpServer::GetInstance()->SetResponseAddr(fake_tcp_addr,
fake_tcp_port);
// Sets an additional stun server
peer_->SetStunServers(stun_servers);
}
void UseTestStunServer() {
TestStunServer::GetInstance()->Reset();
peer_->SetStunServer(TestStunServer::GetInstance()->addr(),
TestStunServer::GetInstance()->port());
TestStunServer::GetInstance(AF_INET)->Reset();
peer_->SetStunServer(TestStunServer::GetInstance(AF_INET)->addr(),
TestStunServer::GetInstance(AF_INET)->port());
}
// NB: Only does substring matching, watch out for stuff like "1.2.3.4"
@ -1314,7 +1357,7 @@ class IceConnectTest : public ::testing::Test {
}
void UseTestStunServer() {
TestStunServer::GetInstance()->Reset();
TestStunServer::GetInstance(AF_INET)->Reset();
p1_->UseTestStunServer();
p2_->UseTestStunServer();
}
@ -1482,8 +1525,8 @@ class PrioritizerTest : public ::testing::Test {
local_addr.interface.type = type;
local_addr.interface.estimated_speed = estimated_speed;
int r = nr_ip4_str_port_to_transport_addr(str_addr.c_str(), 0,
IPPROTO_UDP, &(local_addr.addr));
int r = nr_str_port_to_transport_addr(str_addr.c_str(), 0,
IPPROTO_UDP, &(local_addr.addr));
ASSERT_EQ(0, r);
strncpy(local_addr.addr.ifname, ifname.c_str(), MAXIFNAME);
@ -1791,12 +1834,48 @@ TEST_F(IceGatherTest, VerifyTestStunTcpServer) {
" tcptype "));
}
TEST_F(IceGatherTest, VerifyTestStunServerV6) {
if (!TestStunServer::GetInstance(AF_INET6)) {
// No V6 addresses
return;
}
UseFakeStunUdpServerWithResponse("beef::", 3333);
Gather();
ASSERT_TRUE(StreamHasMatchingCandidate(0, " beef:: 3333 "));
}
TEST_F(IceGatherTest, VerifyTestStunServerFQDN) {
UseFakeStunUdpServerWithResponse("192.0.2.133", 3333, "stun.example.com");
Gather();
ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.2.133 3333 "));
}
TEST_F(IceGatherTest, VerifyTestStunServerV6FQDN) {
if (!TestStunServer::GetInstance(AF_INET6)) {
// No V6 addresses
return;
}
UseFakeStunUdpServerWithResponse("beef::", 3333, "stun.example.com");
Gather();
ASSERT_TRUE(StreamHasMatchingCandidate(0, " beef:: 3333 "));
}
TEST_F(IceGatherTest, TestStunServerReturnsWildcardAddr) {
UseFakeStunUdpServerWithResponse("0.0.0.0", 3333);
Gather(kDefaultTimeout * 3);
ASSERT_FALSE(StreamHasMatchingCandidate(0, " 0.0.0.0 "));
}
TEST_F(IceGatherTest, TestStunServerReturnsWildcardAddrV6) {
if (!TestStunServer::GetInstance(AF_INET6)) {
// No V6 addresses
return;
}
UseFakeStunUdpServerWithResponse("::", 3333);
Gather(kDefaultTimeout * 3);
ASSERT_FALSE(StreamHasMatchingCandidate(0, " :: "));
}
TEST_F(IceGatherTest, TestStunServerReturnsPort0) {
UseFakeStunUdpServerWithResponse("192.0.2.133", 0);
Gather(kDefaultTimeout * 3);
@ -1809,35 +1888,45 @@ TEST_F(IceGatherTest, TestStunServerReturnsLoopbackAddr) {
ASSERT_FALSE(StreamHasMatchingCandidate(0, " 127.0.0.133 "));
}
TEST_F(IceGatherTest, TestStunServerReturnsLoopbackAddrV6) {
if (!TestStunServer::GetInstance(AF_INET6)) {
// No V6 addresses
return;
}
UseFakeStunUdpServerWithResponse("::1", 3333);
Gather(kDefaultTimeout * 3);
ASSERT_FALSE(StreamHasMatchingCandidate(0, " ::1 "));
}
TEST_F(IceGatherTest, TestStunServerTrickle) {
UseFakeStunUdpServerWithResponse("192.0.2.1", 3333);
TestStunServer::GetInstance()->SetActive(false);
TestStunServer::GetInstance(AF_INET)->SetActive(false);
Gather(0);
ASSERT_FALSE(StreamHasMatchingCandidate(0, "192.0.2.1"));
TestStunServer::GetInstance()->SetActive(true);
TestStunServer::GetInstance(AF_INET)->SetActive(true);
WaitForGather();
ASSERT_TRUE(StreamHasMatchingCandidate(0, "192.0.2.1"));
}
TEST_F(IceGatherTest, TestStunTcpServerTrickle) {
UseFakeStunTcpServerWithResponse("192.0.3.1", 3333);
TestStunTcpServer::GetInstance()->SetActive(false);
TestStunTcpServer::GetInstance(AF_INET)->SetActive(false);
Gather(0);
ASSERT_FALSE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
TestStunTcpServer::GetInstance()->SetActive(true);
TestStunTcpServer::GetInstance(AF_INET)->SetActive(true);
WaitForGather();
ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
}
TEST_F(IceGatherTest, TestStunTcpAndUdpServerTrickle) {
UseFakeStunUdpTcpServersWithResponse("192.0.2.1", 3333, "192.0.3.1", 3333);
TestStunServer::GetInstance()->SetActive(false);
TestStunTcpServer::GetInstance()->SetActive(false);
TestStunServer::GetInstance(AF_INET)->SetActive(false);
TestStunTcpServer::GetInstance(AF_INET)->SetActive(false);
Gather(0);
ASSERT_FALSE(StreamHasMatchingCandidate(0, "192.0.2.1", "UDP"));
ASSERT_FALSE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
TestStunServer::GetInstance()->SetActive(true);
TestStunTcpServer::GetInstance()->SetActive(true);
TestStunServer::GetInstance(AF_INET)->SetActive(true);
TestStunTcpServer::GetInstance(AF_INET)->SetActive(true);
WaitForGather();
ASSERT_TRUE(StreamHasMatchingCandidate(0, "192.0.2.1", "UDP"));
ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
@ -2863,10 +2952,18 @@ int main(int argc, char **argv)
listeners.Append(new test::RingbufferDumper(test_utils));
test_utils->sts_target()->Dispatch(
WrapRunnableNM(&TestStunServer::GetInstance), NS_DISPATCH_SYNC);
WrapRunnableNM(&TestStunServer::GetInstance, AF_INET),
NS_DISPATCH_SYNC);
test_utils->sts_target()->Dispatch(
WrapRunnableNM(&TestStunServer::GetInstance, AF_INET6),
NS_DISPATCH_SYNC);
test_utils->sts_target()->Dispatch(
WrapRunnableNM(&TestStunTcpServer::GetInstance), NS_DISPATCH_SYNC);
WrapRunnableNM(&TestStunTcpServer::GetInstance, AF_INET),
NS_DISPATCH_SYNC);
test_utils->sts_target()->Dispatch(
WrapRunnableNM(&TestStunTcpServer::GetInstance, AF_INET6),
NS_DISPATCH_SYNC);
int rv = RUN_ALL_TESTS();

View File

@ -112,7 +112,7 @@ class MultiTcpSocketTest : public ::testing::Test {
r = 1;
for (int tries=10; tries && r; --tries) {
r = nr_ip4_str_port_to_transport_addr(
r = nr_str_port_to_transport_addr(
(char *)"127.0.0.1", EnsureEphemeral(port_s++), IPPROTO_TCP, &local);
ASSERT_EQ(0, r);

View File

@ -84,7 +84,7 @@ class DummyResolver {
void **handle) {
nr_transport_addr addr;
nr_ip4_str_port_to_transport_addr(
nr_str_port_to_transport_addr(
(char *)kProxyAddr.c_str(), kProxyPort, IPPROTO_TCP, &addr);
cb(cb_arg, &addr);
@ -120,11 +120,11 @@ class ProxyTunnelSocketTest : public ::testing::Test {
nr_resolver_ = resolver_impl_.get_nr_resolver();
int r = nr_ip4_str_port_to_transport_addr(
int r = nr_str_port_to_transport_addr(
(char *)kRemoteAddr.c_str(), kRemotePort, IPPROTO_TCP, &remote_addr_);
ASSERT_EQ(0, r);
r = nr_ip4_str_port_to_transport_addr(
r = nr_str_port_to_transport_addr(
(char *)kProxyAddr.c_str(), kProxyPort, IPPROTO_TCP, &proxy_addr_);
ASSERT_EQ(0, r);

View File

@ -188,6 +188,8 @@ int nr_socket_wrapped_create(nr_socket *inner, nr_socket **outp) {
// we have no reason to expect this will be initted to a nullptr yet.
TestStunServer* TestStunServer::instance;
TestStunTcpServer* TestStunTcpServer::instance;
TestStunServer* TestStunServer::instance6;
TestStunTcpServer* TestStunTcpServer::instance6;
uint16_t TestStunServer::instance_port = 3478;
uint16_t TestStunTcpServer::instance_port = 3478;
@ -243,12 +245,14 @@ int TestStunServer::TryOpenListenSocket(nr_local_addr* addr, uint16_t port) {
return 0;
}
int TestStunServer::Initialize() {
nr_local_addr addrs[100];
int TestStunServer::Initialize(int address_family) {
static const size_t max_addrs = 100;
nr_local_addr addrs[max_addrs];
int addr_ct;
int r;
int i;
r = nr_stun_find_local_addresses(addrs, 100, &addr_ct);
r = nr_stun_find_local_addresses(addrs, max_addrs, &addr_ct);
if (r) {
MOZ_MTLOG(ML_ERROR, "Couldn't retrieve addresses");
return R_INTERNAL;
@ -259,10 +263,21 @@ int TestStunServer::Initialize() {
return R_INTERNAL;
}
for (i = 0; i < addr_ct; ++i) {
if (addrs[i].addr.addr->sa_family == address_family) {
break;
}
}
if (i == addr_ct) {
MOZ_MTLOG(ML_ERROR, "No local addresses of the configured IP version");
return R_INTERNAL;
}
int tries = 100;
while (tries--) {
// Bind to the first address (arbitrarily) on configured port (default 3478)
r = TryOpenListenSocket(&addrs[0], instance_port);
// Bind on configured port (default 3478)
r = TryOpenListenSocket(&addrs[i], instance_port);
// We interpret R_ALREADY to mean the addr is probably in use. Try another.
// Otherwise, it either worked or it didn't, and we check below.
if (r != R_ALREADY) {
@ -291,7 +306,7 @@ int TestStunServer::Initialize() {
// Cache the address and port.
char addr_string[INET6_ADDRSTRLEN];
r = nr_transport_addr_get_addrstring(&addrs[0].addr, addr_string,
r = nr_transport_addr_get_addrstring(&addrs[i].addr, addr_string,
sizeof(addr_string));
if (r) {
MOZ_MTLOG(ML_ERROR, "Failed to convert listen addr to a string representation");
@ -304,12 +319,12 @@ int TestStunServer::Initialize() {
return 0;
}
TestStunServer* TestStunServer::Create() {
TestStunServer* TestStunServer::Create(int address_family) {
NR_reg_init(NR_REG_MODE_LOCAL);
ScopedDeletePtr<TestStunServer> server(new TestStunServer());
if (server->Initialize())
if (server->Initialize(address_family))
return nullptr;
NR_SOCKET fd;
@ -328,18 +343,29 @@ void TestStunServer::ConfigurePort(uint16_t port) {
instance_port = port;
}
TestStunServer* TestStunServer::GetInstance() {
if (!instance)
instance = Create();
TestStunServer* TestStunServer::GetInstance(int address_family) {
switch (address_family) {
case AF_INET:
if (!instance)
instance = Create(address_family);
MOZ_ASSERT(instance);
return instance;
MOZ_ASSERT(instance);
return instance;
case AF_INET6:
if (!instance6)
instance6 = Create(address_family);
return instance6;
default:
MOZ_CRASH();
}
}
void TestStunServer::ShutdownInstance() {
delete instance;
instance = nullptr;
delete instance6;
instance6 = nullptr;
}
@ -453,9 +479,9 @@ nsresult TestStunServer::SetResponseAddr(const std::string& addr,
uint16_t port) {
nr_transport_addr addr2;
int r = nr_ip4_str_port_to_transport_addr(addr.c_str(),
port, IPPROTO_UDP,
&addr2);
int r = nr_str_port_to_transport_addr(addr.c_str(),
port, IPPROTO_UDP,
&addr2);
if (r)
return NS_ERROR_FAILURE;
@ -479,12 +505,22 @@ void TestStunTcpServer::ConfigurePort(uint16_t port) {
instance_port = port;
}
TestStunTcpServer* TestStunTcpServer::GetInstance() {
if (!instance)
instance = Create();
TestStunTcpServer* TestStunTcpServer::GetInstance(int address_family) {
switch (address_family) {
case AF_INET:
if (!instance)
instance = Create(address_family);
MOZ_ASSERT(instance);
return instance;
MOZ_ASSERT(instance);
return instance;
case AF_INET6:
if (!instance6)
instance6 = Create(address_family);
return instance6;
default:
MOZ_CRASH();
}
}
void TestStunTcpServer::ShutdownInstance() {
@ -523,12 +559,14 @@ int TestStunTcpServer::TryOpenListenSocket(nr_local_addr* addr, uint16_t port) {
return 0;
}
TestStunTcpServer* TestStunTcpServer::Create() {
TestStunTcpServer* TestStunTcpServer::Create(int address_family) {
NR_reg_init(NR_REG_MODE_LOCAL);
ScopedDeletePtr<TestStunTcpServer> server(new TestStunTcpServer());
server->Initialize();
if (server->Initialize(address_family)) {
return nullptr;
}
nr_socket_multi_tcp_set_readable_cb(server->listen_sock_,
&TestStunServer::readable_cb, server.get());

View File

@ -24,12 +24,13 @@ class TestStunServer {
public:
// Generally, you should only call API in this class from the same thread that
// the initial |GetInstance| call was made from.
static TestStunServer *GetInstance();
static TestStunServer *GetInstance(int address_family = AF_INET);
static void ShutdownInstance();
// |ConfigurePort| will only have an effect if called before the first call
// to |GetInstance| (possibly following a |ShutdownInstance| call)
static void ConfigurePort(uint16_t port);
static TestStunServer *Create();
// AF_INET, AF_INET6
static TestStunServer *Create(int address_family);
virtual ~TestStunServer();
@ -59,7 +60,7 @@ class TestStunServer {
timer_handle_(nullptr) {}
int SetInternalPort(nr_local_addr* addr, uint16_t port);
int Initialize();
int Initialize(int address_family);
static void readable_cb(NR_SOCKET sock, int how, void *cb_arg);
private:
@ -82,12 +83,13 @@ class TestStunServer {
std::map<std::string, uint32_t> received_ct_;
static TestStunServer* instance;
static TestStunServer* instance6;
static uint16_t instance_port;
};
class TestStunTcpServer: public TestStunServer {
public:
static TestStunTcpServer *GetInstance();
static TestStunTcpServer *GetInstance(int address_family);
static void ShutdownInstance();
static void ConfigurePort(uint16_t port);
virtual ~TestStunTcpServer();
@ -98,9 +100,10 @@ class TestStunTcpServer: public TestStunServer {
nsRefPtr<NrIceCtx> ice_ctx_;
private:
virtual int TryOpenListenSocket(nr_local_addr* addr, uint16_t port);
static TestStunTcpServer *Create();
static TestStunTcpServer *Create(int address_family);
static TestStunTcpServer* instance;
static TestStunTcpServer* instance6;
static uint16_t instance_port;
};
} // End of namespace mozilla

View File

@ -67,7 +67,7 @@ class TestNrSocketTest : public ::testing::Test {
// is how we simulate a non-natted socket.
nsRefPtr<TestNrSocket> sock(new TestNrSocket(nat ? nat : new TestNat));
nr_transport_addr address;
nr_ip4_str_port_to_transport_addr(ip_str, 0, IPPROTO_UDP, &address);
nr_str_port_to_transport_addr(ip_str, 0, IPPROTO_UDP, &address);
int r = sock->create(&address);
if (r) {
return nullptr;

View File

@ -132,7 +132,7 @@ class TurnClient : public ::testing::Test {
net_socket_ = real_socket_;
}
r = nr_ip4_str_port_to_transport_addr(turn_server_.c_str(), 3478,
r = nr_str_port_to_transport_addr(turn_server_.c_str(), 3478,
protocol_, &addr);
ASSERT_EQ(0, r);
@ -237,10 +237,10 @@ class TurnClient : public ::testing::Test {
std::string host = target.substr(4, offset - 4);
std::string port = target.substr(offset + 1);
r = nr_ip4_str_port_to_transport_addr(host.c_str(),
atoi(port.c_str()),
IPPROTO_UDP,
&addr);
r = nr_str_port_to_transport_addr(host.c_str(),
atoi(port.c_str()),
IPPROTO_UDP,
&addr);
ASSERT_EQ(0, r);
r = nr_turn_client_ensure_perm(turn_ctx_, &addr);
@ -324,10 +324,10 @@ class TurnClient : public ::testing::Test {
std::string host = target.substr(4, offset - 4);
std::string port = target.substr(offset + 1);
r = nr_ip4_str_port_to_transport_addr(host.c_str(),
atoi(port.c_str()),
IPPROTO_UDP,
&addr);
r = nr_str_port_to_transport_addr(host.c_str(),
atoi(port.c_str()),
IPPROTO_UDP,
&addr);
ASSERT_EQ(0, r);
unsigned char test[100];
@ -488,8 +488,8 @@ int main(int argc, char **argv)
}
{
nr_transport_addr addr;
if (nr_ip4_str_port_to_transport_addr(g_turn_server.c_str(), 3478,
IPPROTO_UDP, &addr)) {
if (nr_str_port_to_transport_addr(g_turn_server.c_str(), 3478,
IPPROTO_UDP, &addr)) {
printf("Invalid TURN_SERVER_ADDRESS \"%s\". Only IP numbers supported.\n",
g_turn_server.c_str());
return 0;
@ -504,7 +504,7 @@ int main(int argc, char **argv)
std::string dummy("dummy");
RUN_ON_THREAD(test_utils->sts_target(),
WrapRunnableNM(&NrIceCtx::Create,
dummy, false, false, false, false),
dummy, false, false, false, false, false),
NS_DISPATCH_SYNC);
// Start the tests

View File

@ -37,6 +37,8 @@
# STUN
./src/stun/addrs.c
./src/stun/addrs.h
./src/stun/ifaddrs-android.c
./src/stun/ifaddrs-android.h
./src/stun/nr_socket_turn.c
./src/stun/nr_socket_turn.h
./src/stun/stun.h

View File

@ -88,6 +88,8 @@
# STUN
"./src/stun/addrs.c",
"./src/stun/addrs.h",
"./src/stun/ifaddrs-android.c",
"./src/stun/ifaddrs-android.h",
"./src/stun/nr_socket_turn.c",
"./src/stun/nr_socket_turn.h",
"./src/stun/nr_socket_buffered_stun.c",

View File

@ -64,7 +64,7 @@ static char *RCSSTRING __UNUSED__="$Id: ice_candidate.c,v 1.2 2008/04/28 17:59:0
#include "nr_socket.h"
#include "nr_socket_multi_tcp.h"
static int next_automatic_preference = 224;
static int next_automatic_preference = 127;
static int nr_ice_candidate_initialize2(nr_ice_candidate *cand);
static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand);
@ -470,8 +470,12 @@ int nr_ice_candidate_compute_priority(nr_ice_candidate *cand)
if (r=NR_reg_set2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,next_automatic_preference)){
ABORT(r);
}
interface_preference=next_automatic_preference;
interface_preference=next_automatic_preference << 1;
next_automatic_preference--;
if (cand->base.ip_version == NR_IPV6) {
/* Prefer IPV6 over IPV4 on the same interface. */
interface_preference += 1;
}
}
else {
ABORT(r);
@ -550,6 +554,11 @@ int nr_ice_candidate_initialize(nr_ice_candidate *cand, NR_async_cb ready_cb, vo
cand->state=NR_ICE_CAND_STATE_INITIALIZING;
if(cand->stun_server->type == NR_ICE_STUN_SERVER_TYPE_ADDR) {
if(cand->base.ip_version != cand->stun_server->u.addr.ip_version) {
r_log(LOG_ICE, LOG_INFO, "ICE-CANDIDATE(%s): Skipping srflx/relayed candidate with different IP version (%d) than STUN/TURN server (%d).", cand->label,cand->base.ip_version,cand->stun_server->u.addr.ip_version);
ABORT(R_NOT_FOUND); /* Same error code when DNS lookup fails */
}
/* Just copy the address */
if (r=nr_transport_addr_copy(&cand->stun_server_addr,
&cand->stun_server->u.addr)) {
@ -567,6 +576,17 @@ int nr_ice_candidate_initialize(nr_ice_candidate *cand, NR_async_cb ready_cb, vo
resource.stun_turn=protocol;
resource.transport_protocol=cand->stun_server->transport;
switch (cand->base.ip_version) {
case NR_IPV4:
resource.address_family=AF_INET;
break;
case NR_IPV6:
resource.address_family=AF_INET6;
break;
default:
ABORT(R_BAD_ARGS);
}
/* Try to resolve */
if(!cand->ctx->resolver) {
r_log(LOG_ICE, LOG_ERR, "ICE-CANDIDATE(%s): Can't use DNS names without a resolver", cand->label);

View File

@ -999,6 +999,9 @@ int nr_ice_component_pair_candidate(nr_ice_peer_ctx *pctx, nr_ice_component *pco
continue;
if (lcand->tcp_type == TCP_TYPE_PASSIVE)
continue;
if(pcand->addr.ip_version != lcand->addr.ip_version)
continue;
/*
Two modes, depending on |pair_all_remote|
@ -1334,3 +1337,44 @@ int nr_ice_component_insert_pair(nr_ice_component *pcomp, nr_ice_cand_pair *pair
return(_status);
}
int nr_ice_component_get_default_candidate(nr_ice_component *comp, nr_ice_candidate **candp, int ip_version)
{
int _status;
nr_ice_candidate *cand;
nr_ice_candidate *best_cand = NULL;
/* We have the component. Now find the "best" candidate, making
use of the fact that more "reliable" candidate types have
higher numbers. So, we sort by type and then priority within
type
*/
cand=TAILQ_FIRST(&comp->candidates);
while(cand){
if (cand->state == NR_ICE_CAND_STATE_INITIALIZED &&
cand->addr.ip_version == ip_version) {
if (!best_cand) {
best_cand = cand;
}
else if (best_cand->type < cand->type) {
best_cand = cand;
} else if (best_cand->type == cand->type &&
best_cand->priority < cand->priority) {
best_cand = cand;
}
}
cand=TAILQ_NEXT(cand,entry_comp);
}
/* No candidates */
if (!best_cand)
ABORT(R_NOT_FOUND);
*candp = best_cand;
_status=0;
abort:
return(_status);
}

View File

@ -93,6 +93,7 @@ int nr_ice_component_select_pair(nr_ice_peer_ctx *pctx, nr_ice_component *comp);
int nr_ice_component_set_failed(nr_ice_component *comp);
int nr_ice_component_finalize(nr_ice_component *lcomp, nr_ice_component *rcomp);
int nr_ice_component_insert_pair(nr_ice_component *pcomp, nr_ice_cand_pair *pair);
int nr_ice_component_get_default_candidate(nr_ice_component *comp, nr_ice_candidate **candp, int ip_version);
#ifdef __cplusplus
}

View File

@ -223,14 +223,11 @@ int nr_ice_media_stream_get_attributes(nr_ice_media_stream *stream, char ***attr
return(_status);
}
/* Get a default candidate per 4.1.4 */
int nr_ice_media_stream_get_default_candidate(nr_ice_media_stream *stream, int component, nr_ice_candidate **candp)
{
int _status;
int r,_status;
nr_ice_component *comp;
nr_ice_candidate *cand;
nr_ice_candidate *best_cand = NULL;
comp=STAILQ_FIRST(&stream->components);
while(comp){
@ -243,36 +240,12 @@ int nr_ice_media_stream_get_default_candidate(nr_ice_media_stream *stream, int c
if (!comp)
ABORT(R_NOT_FOUND);
/* We have the component. Now find the "best" candidate, making
use of the fact that more "reliable" candidate types have
higher numbers. So, we sort by type and then priority within
type
*/
cand=TAILQ_FIRST(&comp->candidates);
while(cand){
if (cand->state == NR_ICE_CAND_STATE_INITIALIZED) {
if (!best_cand) {
best_cand = cand;
}
else {
if (best_cand->type < cand->type) {
best_cand = cand;
} else if (best_cand->type == cand->type) {
if (best_cand->priority < cand->priority)
best_cand = cand;
}
}
}
cand=TAILQ_NEXT(cand,entry_comp);
/* If there aren't any IPV4 candidates, try IPV6 */
if((r=nr_ice_component_get_default_candidate(comp, candp, NR_IPV4)) &&
(r=nr_ice_component_get_default_candidate(comp, candp, NR_IPV6))) {
ABORT(r);
}
/* No candidates */
if (!best_cand)
ABORT(R_NOT_FOUND);
*candp = best_cand;
_status=0;
abort:
return(_status);

View File

@ -120,7 +120,6 @@ nr_ice_peer_candidate_from_attribute(nr_ice_ctx *ctx,char *orig,nr_ice_media_str
nr_ice_candidate *cand;
char *connection_address=0;
unsigned int port;
in_addr_t addr;
int i;
unsigned int component_id;
char *rel_addr=0;
@ -212,10 +211,6 @@ nr_ice_peer_candidate_from_attribute(nr_ice_ctx *ctx,char *orig,nr_ice_media_str
if (*str == '\0')
ABORT(R_BAD_DATA);
addr = inet_addr(connection_address);
if (addr == INADDR_NONE)
ABORT(R_BAD_DATA);
skip_whitespace(&str);
if (*str == '\0')
ABORT(R_BAD_DATA);
@ -226,8 +221,7 @@ nr_ice_peer_candidate_from_attribute(nr_ice_ctx *ctx,char *orig,nr_ice_media_str
if (port < 1 || port > 0x0FFFF)
ABORT(R_BAD_DATA);
/* Assume v4 for now */
if(r=nr_ip4_port_to_transport_addr(ntohl(addr),port,transport,&cand->addr))
if ((r=nr_str_port_to_transport_addr(connection_address,port,transport,&cand->addr)))
ABORT(r);
skip_to_past_space(&str);
@ -289,10 +283,6 @@ nr_ice_peer_candidate_from_attribute(nr_ice_ctx *ctx,char *orig,nr_ice_media_str
if (*str == '\0')
ABORT(R_BAD_DATA);
addr = inet_addr(rel_addr);
if (addr == INADDR_NONE)
ABORT(R_BAD_DATA);
skip_whitespace(&str);
if (*str == '\0')
ABORT(R_BAD_DATA);
@ -314,8 +304,7 @@ nr_ice_peer_candidate_from_attribute(nr_ice_ctx *ctx,char *orig,nr_ice_media_str
if (port < 1 || port > 0x0FFFF)
ABORT(R_BAD_DATA);
/* Assume v4 for now */
if(r=nr_ip4_port_to_transport_addr(ntohl(addr),port,transport,&cand->base))
if ((r=nr_str_port_to_transport_addr(rel_addr,port,transport,&cand->base)))
ABORT(r);
skip_to_past_space(&str);

View File

@ -256,7 +256,7 @@ int nr_socket_proxy_tunnel_connect(void *obj, nr_transport_addr *addr)
assert(config->proxy_host);
/* Check if the proxy_host is already an IP address */
has_addr = !nr_ip4_str_port_to_transport_addr(config->proxy_host,
has_addr = !nr_str_port_to_transport_addr(config->proxy_host,
config->proxy_port, IPPROTO_TCP, &proxy_addr);
r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_connect: %s", config->proxy_host);

View File

@ -46,6 +46,7 @@ typedef struct nr_resolver_resource_ {
UINT2 port;
int stun_turn;
UCHAR transport_protocol;
UCHAR address_family;
} nr_resolver_resource;
typedef struct nr_resolver_vtbl_ {

View File

@ -100,44 +100,51 @@ int nr_transport_addr_fmt_ifname_addr_string(const nr_transport_addr *addr, char
if (!inet_ntop(AF_INET, &addr->u.addr4.sin_addr,buffer,sizeof(buffer))) {
strncpy(buffer, "[error]", len);
}
snprintf(buf,len,"%s:%s",addr->ifname,buffer);
break;
case NR_IPV6:
if (!inet_ntop(AF_INET6, &addr->u.addr6.sin6_addr,buffer,sizeof(buffer))) {
strncpy(buffer, "[error]", len);
}
break;
default:
ABORT(R_INTERNAL);
}
snprintf(buf,len,"%s:%s",addr->ifname,buffer);
_status=0;
abort:
return(_status);
}
int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int saddr_len, int protocol, int keep, nr_transport_addr *addr)
int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int protocol, int keep, nr_transport_addr *addr)
{
int r,_status;
if(!keep) memset(addr,0,sizeof(nr_transport_addr));
if(saddr->sa_family==PF_INET){
if(saddr_len != sizeof(struct sockaddr_in))
switch(protocol){
case IPPROTO_TCP:
case IPPROTO_UDP:
break;
default:
ABORT(R_BAD_ARGS);
}
switch(protocol){
case IPPROTO_TCP:
case IPPROTO_UDP:
break;
default:
ABORT(R_BAD_ARGS);
}
addr->protocol=protocol;
if(saddr->sa_family==AF_INET){
addr->ip_version=NR_IPV4;
addr->protocol=protocol;
memcpy(&addr->u.addr4,saddr,sizeof(struct sockaddr_in));
addr->addr=(struct sockaddr *)&addr->u.addr4;
addr->addr_len=saddr_len;
addr->addr_len=sizeof(struct sockaddr_in);
}
else if(saddr->sa_family==PF_INET6){
/* Not implemented */
ABORT(R_INTERNAL);
else if(saddr->sa_family==AF_INET6){
addr->ip_version=NR_IPV6;
memcpy(&addr->u.addr6, saddr, sizeof(struct sockaddr_in6));
addr->addr=(struct sockaddr *)&addr->u.addr6;
addr->addr_len=sizeof(struct sockaddr_in6);
}
else
ABORT(R_BAD_ARGS);
@ -206,16 +213,42 @@ int nr_ip4_port_to_transport_addr(UINT4 ip4, UINT2 port, int protocol, nr_transp
return(_status);
}
int nr_ip4_str_port_to_transport_addr(const char *ip4, UINT2 port, int protocol, nr_transport_addr *addr)
int nr_str_port_to_transport_addr(const char *ip, UINT2 port, int protocol, nr_transport_addr *addr_out)
{
int r,_status;
in_addr_t ip_addr;
struct in_addr addr;
struct in6_addr addr6;
ip_addr=inet_addr(ip4);
if (ip_addr == INADDR_NONE)
if (inet_pton(AF_INET, ip, &addr) == 1) {
if(r=nr_ip4_port_to_transport_addr(ntohl(addr.s_addr),port,protocol,addr_out))
ABORT(r);
} else if (inet_pton(AF_INET6, ip, &addr6) == 1) {
if(r=nr_ip6_port_to_transport_addr(&addr6,port,protocol,addr_out))
ABORT(r);
} else {
ABORT(R_BAD_DATA);
/* Assume v4 for now */
if(r=nr_ip4_port_to_transport_addr(ntohl(ip_addr),port,protocol,addr))
}
_status=0;
abort:
return(_status);
}
int nr_ip6_port_to_transport_addr(struct in6_addr* addr6, UINT2 port, int protocol, nr_transport_addr *addr)
{
int r,_status;
memset(addr, 0, sizeof(nr_transport_addr));
addr->ip_version=NR_IPV6;
addr->protocol=protocol;
addr->u.addr6.sin6_family=PF_INET6;
addr->u.addr6.sin6_port=htons(port);
memcpy(addr->u.addr6.sin6_addr.s6_addr, addr6->s6_addr, sizeof(addr6->s6_addr));
addr->addr=(struct sockaddr *)&addr->u.addr6;
addr->addr_len=sizeof(struct sockaddr_in6);
if(r=nr_transport_addr_fmt_addr_string(addr))
ABORT(r);
_status=0;
@ -291,26 +324,6 @@ int nr_transport_addr_set_port(nr_transport_addr *addr, int port)
return(_status);
}
int nr_transport_addr_get_ip4(nr_transport_addr *addr, UINT4 *ip4p)
{
int _status;
switch(addr->ip_version){
case NR_IPV4:
*ip4p=ntohl(addr->u.addr4.sin_addr.s_addr);
break;
case NR_IPV6:
ABORT(R_NOT_FOUND);
break;
default:
ABORT(R_INTERNAL);
}
_status=0;
abort:
return(_status);
}
/* memcmp() may not work if, for instance, the string or interface
haven't been made. Hmmm.. */
int nr_transport_addr_cmp(nr_transport_addr *addr1,nr_transport_addr *addr2,int mode)
@ -340,7 +353,13 @@ int nr_transport_addr_cmp(nr_transport_addr *addr1,nr_transport_addr *addr2,int
return(1);
break;
case NR_IPV6:
UNIMPLEMENTED;
if(memcmp(addr1->u.addr6.sin6_addr.s6_addr,addr2->u.addr6.sin6_addr.s6_addr,sizeof(struct in6_addr)))
return(1);
if(mode < NR_TRANSPORT_ADDR_CMP_MODE_ALL)
return(0);
if(addr1->u.addr6.sin6_port != addr2->u.addr6.sin6_port)
return(1);
break;
default:
abort();
}
@ -363,6 +382,10 @@ int nr_transport_addr_is_loopback(nr_transport_addr *addr)
}
break;
case NR_IPV6:
if(!memcmp(addr->u.addr6.sin6_addr.s6_addr,in6addr_loopback.s6_addr,sizeof(struct in6_addr)))
return(1);
break;
default:
UNIMPLEMENTED;
}
@ -370,6 +393,18 @@ int nr_transport_addr_is_loopback(nr_transport_addr *addr)
return(0);
}
int nr_transport_addr_is_link_local(nr_transport_addr *addr)
{
if(addr->ip_version == NR_IPV6){
UINT4* addrTop = (UINT4*)(addr->u.addr6.sin6_addr.s6_addr);
return ((*addrTop & htonl(0xFFC00000)) == htonl(0xFE800000));
} else {
assert(0);
}
return(0);
}
int nr_transport_addr_is_wildcard(nr_transport_addr *addr)
{
switch(addr->ip_version){
@ -379,6 +414,12 @@ int nr_transport_addr_is_wildcard(nr_transport_addr *addr)
if(addr->u.addr4.sin_port==0)
return(1);
break;
case NR_IPV6:
if(!memcmp(addr->u.addr6.sin6_addr.s6_addr,in6addr_any.s6_addr,sizeof(struct in6_addr)))
return(1);
if(addr->u.addr6.sin6_port==0)
return(1);
break;
default:
UNIMPLEMENTED;
}

View File

@ -71,15 +71,15 @@ typedef struct nr_transport_addr_ {
char as_string[56];
} nr_transport_addr;
int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int saddr_len, int protocol, int keep, nr_transport_addr *addr);
int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int protocol, int keep, nr_transport_addr *addr);
// addresses, ports in local byte order
int nr_ip4_port_to_transport_addr(UINT4 ip4, UINT2 port, int protocol, nr_transport_addr *addr);
int nr_ip4_str_port_to_transport_addr(const char *ip4, UINT2 port, int protocol, nr_transport_addr *addr);
int nr_str_port_to_transport_addr(const char *ip4, UINT2 port, int protocol, nr_transport_addr *addr);
int nr_ip6_port_to_transport_addr(struct in6_addr* addr6, UINT2 port, int protocol, nr_transport_addr *addr);
int nr_transport_addr_get_addrstring(nr_transport_addr *addr, char *str, int maxlen);
int nr_transport_addr_get_port(nr_transport_addr *addr, int *port);
int nr_transport_addr_get_ip4(nr_transport_addr *addr, UINT4 *ip4p);
int nr_transport_addr_cmp(nr_transport_addr *addr1,nr_transport_addr *addr2,int mode);
#define NR_TRANSPORT_ADDR_CMP_MODE_VERSION 1
#define NR_TRANSPORT_ADDR_CMP_MODE_PROTOCOL 2
@ -88,6 +88,7 @@ int nr_transport_addr_cmp(nr_transport_addr *addr1,nr_transport_addr *addr2,int
int nr_transport_addr_is_wildcard(nr_transport_addr *addr);
int nr_transport_addr_is_loopback(nr_transport_addr *addr);
int nr_transport_addr_is_link_local(nr_transport_addr *addr);
int nr_transport_addr_copy(nr_transport_addr *to, nr_transport_addr *from);
int nr_transport_addr_copy_keep_ifname(nr_transport_addr *to, nr_transport_addr *from);
int nr_transport_addr_fmt_addr_string(nr_transport_addr *addr);

View File

@ -53,6 +53,9 @@ static char *RCSSTRING __UNUSED__="$Id: transport_addr_reg.c,v 1.2 2008/04/28 17
#include "transport_addr.h"
#include "transport_addr_reg.h"
#ifndef INET6_ADDRSTRLEN
#define INET6_ADDRSTRLEN 46 /* Value used by linux/BSD */
#endif
int
nr_reg_get_transport_addr(NR_registry prefix, int keep, nr_transport_addr *addr)
@ -107,7 +110,7 @@ nr_reg_get_transport_addr(NR_registry prefix, int keep, nr_transport_addr *addr)
if (!keep) memset(addr, 0, sizeof(*addr));
if ((r=nr_ip4_str_port_to_transport_addr(address?address:"0.0.0.0", port, p, addr)))
if ((r=nr_str_port_to_transport_addr(address?address:"0.0.0.0", port, p, addr)))
ABORT(r);
if (ifname)
@ -133,7 +136,7 @@ nr_reg_set_transport_addr(NR_registry prefix, int keep, nr_transport_addr *addr)
switch (addr->ip_version) {
case NR_IPV4:
if (addr->u.addr4.sin_addr.s_addr != INADDR_ANY) {
if (!nr_transport_addr_is_wildcard(addr)) {
if ((r=NR_reg_set2_string(prefix, "address", inet_ntoa(addr->u.addr4.sin_addr))))
ABORT(r);
}
@ -142,35 +145,50 @@ nr_reg_set_transport_addr(NR_registry prefix, int keep, nr_transport_addr *addr)
if ((r=NR_reg_set2_uint2(prefix, "port", ntohs(addr->u.addr4.sin_port))))
ABORT(r);
}
switch (addr->protocol) {
case IPPROTO_TCP:
if ((r=NR_reg_set2_string(prefix, "protocol", "tcp")))
ABORT(r);
break;
case IPPROTO_UDP:
if ((r=NR_reg_set2_string(prefix, "protocol", "udp")))
ABORT(r);
break;
default:
UNIMPLEMENTED;
break;
}
if (strlen(addr->ifname) > 0) {
if ((r=NR_reg_set2_string(prefix, "ifname", addr->ifname)))
ABORT(r);
}
break;
case NR_IPV6:
UNIMPLEMENTED;
if (!nr_transport_addr_is_wildcard(addr)) {
char address[INET6_ADDRSTRLEN];
if(!inet_ntop(AF_INET6, &addr->u.addr6.sin6_addr,address,sizeof(address))) {
ABORT(R_BAD_DATA);
}
if ((r=NR_reg_set2_string(prefix, "address", address))) {
ABORT(r);
}
}
if (addr->u.addr6.sin6_port != 0) {
if ((r=NR_reg_set2_uint2(prefix, "port", ntohs(addr->u.addr6.sin6_port))))
ABORT(r);
}
break;
default:
ABORT(R_INTERNAL);
break;
}
/* We abort if neither NR_IPV4 or NR_IPV6 above */
switch (addr->protocol) {
case IPPROTO_TCP:
if ((r=NR_reg_set2_string(prefix, "protocol", "tcp")))
ABORT(r);
break;
case IPPROTO_UDP:
if ((r=NR_reg_set2_string(prefix, "protocol", "udp")))
ABORT(r);
break;
default:
UNIMPLEMENTED;
break;
}
if (strlen(addr->ifname) > 0) {
if ((r=NR_reg_set2_string(prefix, "ifname", addr->ifname)))
ABORT(r);
}
_status=0;
abort:
if (_status)

View File

@ -41,267 +41,42 @@ static char *RCSSTRING __UNUSED__="$Id: addrs.c,v 1.2 2008/04/28 18:21:30 ekr Ex
#include <winsock2.h>
#include <iphlpapi.h>
#include <tchar.h>
#else /* UNIX */
#include <sys/param.h>
#else /* !WIN32 */
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <errno.h>
#ifndef ANDROID
#include <sys/syslog.h>
/* This works on linux and BSD, but not android */
#include <sys/types.h> /* getifaddrs */
#include <ifaddrs.h> /* getifaddrs */
#else
#include <syslog.h>
#include "ifaddrs-android.h"
#define getifaddrs android_getifaddrs
#define freeifaddrs android_freeifaddrs
#endif
#ifdef LINUX
#ifdef ANDROID
/* Work around an Android NDK < r8c bug */
#undef __unused
#endif
#ifndef LINUX
#include <net/if.h>
#if !defined(__OpenBSD__) && !defined(__NetBSD__)
#include <net/if_var.h>
#endif
#include <net/if_dl.h>
#include <net/if_types.h>
#include <sys/sockio.h>
#else
#include <linux/sockios.h>
#include <linux/if.h>
#include <linux/kernel.h>
#include <linux/wireless.h>
#ifndef ANDROID
#include <linux/ethtool.h>
#endif
#endif
#include <net/route.h>
#include <linux/if.h> /* struct ifreq, IFF_POINTTOPOINT */
#include <linux/wireless.h> /* struct iwreq */
#include <linux/ethtool.h> /* struct ethtool_cmd */
#include <linux/sockios.h> /* SIOCETHTOOL */
#endif /* ANDROID */
/* IP */
#include <netinet/in.h>
#ifdef LINUX
#include "sys/ioctl.h"
#else
#include <netinet/in_var.h>
#endif
#include <arpa/inet.h>
#include <netdb.h>
#endif /* UNIX */
#endif /* LINUX */
#endif /* !WIN32 */
#include "stun.h"
#include "addrs.h"
#if defined(BSD) || defined(DARWIN)
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*[3 Deleted as of 22nd July 1999; see
* ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
* for details]
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <err.h>
#include <sys/sysctl.h>
static void stun_rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
static int stun_grab_addrs(char *name, int addrcount,
struct ifa_msghdr *ifam,
nr_local_addr addrs[], int maxaddrs, int *count);
static int
nr_stun_is_duplicate_addr(nr_local_addr addrs[], int count, nr_local_addr *addr);
/*
* Expand the compacted form of addresses as returned via the
* configuration read via sysctl().
*/
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
static void
stun_rt_xaddrs(cp, cplim, rtinfo)
caddr_t cp, cplim;
struct rt_addrinfo *rtinfo;
{
struct sockaddr *sa;
int i;
memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
if ((rtinfo->rti_addrs & (1 << i)) == 0)
continue;
rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
ADVANCE(cp, sa);
}
}
static int
stun_grab_addrs(char *name, int addrcount, struct ifa_msghdr *ifam, nr_local_addr addrs[], int maxaddrs, int *count)
{
int r,_status;
int s = -1;
struct ifreq ifr;
struct rt_addrinfo info;
struct sockaddr_in *sin;
ifr.ifr_addr.sa_family = AF_INET;
strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) {
r_log(NR_LOG_STUN, LOG_ERR, "unable to obtain addresses from socket");
ABORT(R_FAILED);
}
while (addrcount > 0) {
info.rti_addrs = ifam->ifam_addrs;
/* Expand the compacted addresses */
stun_rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info);
addrs[*count].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
addrs[*count].interface.estimated_speed = 0;
/* TODO (Bug 895790) Get interface properties for Darwin */
switch (info.rti_info[RTAX_IFA]->sa_family) {
case AF_INET:
sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA];
if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sin, sizeof(*sin), IPPROTO_UDP, 0, &(addrs[*count].addr))))
ABORT(r);
strlcpy(addrs[*count].addr.ifname, name, sizeof(addrs[*count].addr.ifname));
++*count;
break;
case AF_INET6:
UNIMPLEMENTED;
break;
}
addrcount--;
if (*count >= maxaddrs) {
r_log(NR_LOG_STUN, LOG_WARNING, "Address list truncated at %d out of %d entries", maxaddrs, maxaddrs+addrcount);
break;
}
ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
}
_status = 0;
abort:
if (s != -1) close(s);
return _status;
}
static int
stun_get_mib_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
{
int _status;
char name[32];
int flags;
int addrcount;
struct if_msghdr *ifm, *nextifm;
struct ifa_msghdr *ifam;
struct sockaddr_dl *sdl;
char *buf = 0;
char *lim;
char *next;
size_t needed;
int mib[6];
*count = 0;
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = AF_INET;
mib[4] = NET_RT_IFLIST;
mib[5] = 0;
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
errx(1, "iflist-sysctl-estimate");
ABORT(R_INTERNAL);
}
if ((buf = malloc(needed)) == NULL) {
errx(1, "malloc");
ABORT(R_NO_MEMORY);
}
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
errx(1, "actual retrieval of interface table");
ABORT(R_INTERNAL);
}
lim = buf + needed;
next = buf;
while (next < lim) {
ifm = (struct if_msghdr *)next;
if (ifm->ifm_type == RTM_IFINFO) {
sdl = (struct sockaddr_dl *)(ifm + 1);
flags = ifm->ifm_flags;
} else {
r_log(NR_LOG_STUN, LOG_WARNING, "out of sync parsing NET_RT_IFLIST");
r_log(NR_LOG_STUN, LOG_DEBUG, "expected %d, got %d, msglen = %d, buf:%p, next:%p, lim:%p", RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen, buf, next, lim);
ABORT(R_FAILED);
}
next += ifm->ifm_msglen;
ifam = NULL;
addrcount = 0;
while (next < lim) {
nextifm = (struct if_msghdr *)next;
if (nextifm->ifm_type != RTM_NEWADDR)
break;
if (ifam == NULL)
ifam = (struct ifa_msghdr *)nextifm;
addrcount++;
next += nextifm->ifm_msglen;
}
if (sdl->sdl_nlen > sizeof(name) - 1) {
ABORT(R_INTERNAL);
}
memcpy(name, sdl->sdl_data, sdl->sdl_nlen);
name[sdl->sdl_nlen] = '\0';
stun_grab_addrs(name, addrcount, ifam, addrs, maxaddrs, count);
}
_status = 0;
abort:
if (buf) free(buf);
return _status;
}
#elif defined(WIN32)
#if defined(WIN32)
#define WIN32_MAX_NUM_INTERFACES 20
@ -368,125 +143,6 @@ abort:
return(_status);
}
static int
stun_get_win32_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
{
int r,_status;
PIP_ADAPTER_INFO pAdapterInfo;
PIP_ADAPTER_INFO pAdapter = NULL;
PIP_ADDR_STRING pAddrString;
ULONG out_buf_len;
char *friendly_name=0;
char munged_ifname[IFNAMSIZ];
int n = 0;
*count = 0;
pAdapterInfo = (IP_ADAPTER_INFO *) RMALLOC(sizeof(IP_ADAPTER_INFO));
out_buf_len = sizeof(IP_ADAPTER_INFO);
/* First call to GetAdaptersInfo is mainly to get length */
if (GetAdaptersInfo(pAdapterInfo, &out_buf_len) == ERROR_BUFFER_OVERFLOW) {
RFREE(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *) RMALLOC(out_buf_len);
if (pAdapterInfo == NULL) {
r_log(NR_LOG_STUN, LOG_ERR, "Error allocating memory for GetAdaptersInfo output");
ABORT(R_NO_MEMORY);
}
}
if ((r = GetAdaptersInfo(pAdapterInfo, &out_buf_len)) != NO_ERROR) {
r_log(NR_LOG_STUN, LOG_ERR, "Got error from GetAdaptersInfo");
ABORT(R_INTERNAL);
}
r_log(NR_LOG_STUN, LOG_DEBUG, "Got AdaptersInfo");
pAdapter = pAdapterInfo;
while (pAdapter) {
char *c;
r_log(NR_LOG_STUN, LOG_DEBUG, "Adapter Name (GUID) = %s", pAdapter->AdapterName);
r_log(NR_LOG_STUN, LOG_DEBUG, "Adapter Description = %s", pAdapter->Description);
if (nr_win32_get_adapter_friendly_name(pAdapter->AdapterName, &friendly_name)) {
friendly_name = 0;
}
if (friendly_name && *friendly_name) {
r_log(NR_LOG_STUN, LOG_INFO, "Found adapter with friendly name: %s", friendly_name);
snprintf(munged_ifname, IFNAMSIZ, "%s%c", friendly_name, 0);
RFREE(friendly_name);
friendly_name = 0;
} else {
// Not all adapters follow the friendly name convention. Windows' PPTP
// VPN adapter puts "VPN Connection 2" in the Description field instead.
// Windows's renaming-logic appears to enforce uniqueness in spite of this.
r_log(NR_LOG_STUN, LOG_INFO, "Found adapter with description: %s", pAdapter->Description);
snprintf(munged_ifname, IFNAMSIZ, "%s%c", pAdapter->Description, 0);
}
/* replace spaces with underscores */
c = strchr(munged_ifname, ' ');
while (c != NULL) {
*c = '_';
c = strchr(munged_ifname, ' ');
}
c = strchr(munged_ifname, '.');
while (c != NULL) {
*c = '+';
c = strchr(munged_ifname, '.');
}
r_log(NR_LOG_STUN, LOG_INFO, "Converted ifname: %s", munged_ifname);
for (pAddrString = &(pAdapter->IpAddressList); pAddrString != NULL; pAddrString = pAddrString->Next) {
unsigned long this_addr = inet_addr(pAddrString->IpAddress.String);
nr_transport_addr *addr = &(addrs[n].addr);
if (this_addr == 0)
continue;
r_log(NR_LOG_STUN, LOG_INFO, "Adapter %s address: %s", munged_ifname, pAddrString->IpAddress.String);
addr->ip_version=NR_IPV4;
addr->protocol = IPPROTO_UDP;
addr->u.addr4.sin_family=PF_INET;
addr->u.addr4.sin_port=0;
addr->u.addr4.sin_addr.s_addr=this_addr;
addr->addr=(struct sockaddr *)&(addr->u.addr4);
addr->addr_len=sizeof(struct sockaddr_in);
strlcpy(addr->ifname, munged_ifname, sizeof(addr->ifname));
snprintf(addr->as_string,40,"IP4:%s:%d",
inet_ntoa(addr->u.addr4.sin_addr),
ntohs(addr->u.addr4.sin_port));
/* TODO: (Bug 895793) Getting interface properties for Windows */
addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
addrs[n].interface.estimated_speed = 0;
if (++n >= maxaddrs)
goto done;
}
pAdapter = pAdapter->Next;
}
done:
*count = n;
_status = 0;
abort:
RFREE(pAdapterInfo);
RFREE(friendly_name);
return _status;
}
#ifdef GET_WIN32_ADDRS_NO_WIN2K
/* Here's a nice way to get adapter addresses and names, but it
* isn't supported on Win2000.
*/
static int
stun_get_win32_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
{
@ -505,7 +161,7 @@ stun_get_win32_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
buflen = 0;
r = GetAdaptersAddresses(AF_INET, 0, NULL, AdapterAddresses, &buflen);
r = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, AdapterAddresses, &buflen);
if (r != ERROR_BUFFER_OVERFLOW) {
r_log(NR_LOG_STUN, LOG_ERR, "Error getting buf len from GetAdaptersAddresses()");
ABORT(R_INTERNAL);
@ -519,7 +175,7 @@ stun_get_win32_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
/* for real, this time */
r = GetAdaptersAddresses(AF_INET, 0, NULL, AdapterAddresses, &buflen);
r = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, AdapterAddresses, &buflen);
if (r != NO_ERROR) {
r_log(NR_LOG_STUN, LOG_ERR, "Error getting addresses from GetAdaptersAddresses()");
ABORT(R_INTERNAL);
@ -554,7 +210,7 @@ stun_get_win32_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
if ((sa_addr->lpSockaddr->sa_family == AF_INET) ||
(sa_addr->lpSockaddr->sa_family == AF_INET6)) {
if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sa_addr->lpSockaddr, sizeof(*sa_addr->lpSockaddr), IPPROTO_UDP, 0, &(addrs[n].addr))))
if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sa_addr->lpSockaddr, IPPROTO_UDP, 0, &(addrs[n].addr))))
ABORT(r);
}
else {
@ -580,131 +236,98 @@ stun_get_win32_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
RFREE(AdapterAddresses);
return _status;
}
#endif /* GET_WIN32_ADDRS_NO_WIN2K */
#elif defined(__sparc__)
#else /* WIN32 */
static int
stun_get_sparc_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
{
*count = 0;
UNIMPLEMENTED; /*TODO !nn! - sparc */
return 0;
}
#else
nr_stun_is_duplicate_addr(nr_local_addr addrs[], int count, nr_local_addr *addr);
static int
stun_get_siocgifconf_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
stun_getifaddrs(nr_local_addr addrs[], int maxaddrs, int *count)
{
struct ifconf ifc;
int _status;
int s = socket( AF_INET, SOCK_DGRAM, 0 );
int len = 100 * sizeof(struct ifreq);
int r;
int e;
char *ptr;
int tl;
int n;
struct ifreq ifr2;
int r,_status;
struct ifaddrs* if_addrs_head=NULL;
struct ifaddrs* if_addr;
char buf[ len ];
*count=0;
ifc.ifc_len = len;
ifc.ifc_buf = buf;
if (getifaddrs(&if_addrs_head) == -1) {
r_log(NR_LOG_STUN, LOG_ERR, "getifaddrs error e = %d", errno);
ABORT(R_INTERNAL);
}
e = ioctl(s,SIOCGIFCONF,&ifc);
if_addr = if_addrs_head;
if ( e == -1 )
{
return(R_INTERNAL);
}
ptr = buf;
tl = ifc.ifc_len;
n=0;
while ( (tl > 0) && ( n < maxaddrs) )
{
struct ifreq* ifr = (struct ifreq *)ptr;
#ifdef LINUX
int si = sizeof(struct ifreq);
#ifndef ANDROID
struct ethtool_cmd ecmd;
struct iwreq wrq;
#endif
#else
int si = sizeof(ifr->ifr_name) + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr));
#endif
tl -= si;
ptr += si;
ifr2 = *ifr;
e = ioctl(s,SIOCGIFADDR,&ifr2);
if ( e == -1 )
{
continue;
}
//r_log(NR_LOG_STUN, LOG_ERR, "ioctl addr e = %d",e);
if ((r=nr_sockaddr_to_transport_addr(&ifr2.ifr_addr, sizeof(ifr2.ifr_addr), IPPROTO_UDP, 0, &(addrs[n].addr)))) {
r_log(NR_LOG_STUN, LOG_WARNING, "Problem transforming address");
}
else {
addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
addrs[n].interface.estimated_speed = 0;
while (if_addr && *count < maxaddrs) {
switch (if_addr->ifa_addr->sa_family) {
case AF_INET:
case AF_INET6:
if (r=nr_sockaddr_to_transport_addr(if_addr->ifa_addr, IPPROTO_UDP, 0, &(addrs[*count].addr))) {
r_log(NR_LOG_STUN, LOG_ERR, "nr_sockaddr_to_transport_addr error r = %d", r);
} else {
#if defined(LINUX) && !defined(ANDROID)
struct ethtool_cmd ecmd;
struct ifreq ifr;
struct iwreq wrq;
int e;
int s = socket(AF_INET, SOCK_DGRAM, 0);
strncpy(ifr.ifr_name, if_addr->ifa_name, sizeof(ifr.ifr_name));
/* TODO (Bug 896851): interface property for Android */
/* Getting ethtool for ethernet information. */
ecmd.cmd = ETHTOOL_GSET;
ifr2.ifr_data = (void*)&ecmd;
e = ioctl(s, SIOCETHTOOL, &ifr2);
/* In/out param */
ifr.ifr_data = (void*)&ecmd;
e = ioctl(s, SIOCETHTOOL, &ifr);
if (e == 0)
{
/* For wireless network, we won't get ethtool, it's a wired
connection */
addrs[n].interface.type = NR_INTERFACE_TYPE_WIRED;
* connection */
addrs[*count].interface.type = NR_INTERFACE_TYPE_WIRED;
#ifdef DONT_HAVE_ETHTOOL_SPEED_HI
addrs[n].interface.estimated_speed = ecmd.speed;
addrs[*count].interface.estimated_speed = ecmd.speed;
#else
addrs[n].interface.estimated_speed = ((ecmd.speed_hi << 16) | ecmd.speed) * 1000;
addrs[*count].interface.estimated_speed = ((ecmd.speed_hi << 16) | ecmd.speed) * 1000;
#endif
}
strncpy(wrq.ifr_name, ifr->ifr_name, sizeof(wrq.ifr_name));
strncpy(wrq.ifr_name, if_addr->ifa_name, sizeof(wrq.ifr_name));
e = ioctl(s, SIOCGIWRATE, &wrq);
if (e == 0)
{
addrs[n].interface.type = NR_INTERFACE_TYPE_WIFI;
addrs[n].interface.estimated_speed = wrq.u.bitrate.value / 1000;
addrs[*count].interface.type = NR_INTERFACE_TYPE_WIFI;
addrs[*count].interface.estimated_speed = wrq.u.bitrate.value / 1000;
}
ifr2 = *ifr;
e = ioctl(s, SIOCGIFFLAGS, &ifr2);
if (e == 0)
if (if_addr->ifa_flags & IFF_POINTOPOINT)
{
if (ifr2.ifr_flags & IFF_POINTOPOINT)
{
addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN | NR_INTERFACE_TYPE_VPN;
/* TODO (Bug 896913): find backend network type of this VPN */
}
addrs[*count].interface.type = NR_INTERFACE_TYPE_UNKNOWN | NR_INTERFACE_TYPE_VPN;
/* TODO (Bug 896913): find backend network type of this VPN */
}
#else
addrs[*count].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
addrs[*count].interface.estimated_speed = 0;
#endif
strlcpy(addrs[n].addr.ifname, ifr->ifr_name, sizeof(addrs[n].addr.ifname));
++n;
}
}
strlcpy(addrs[*count].addr.ifname, if_addr->ifa_name, sizeof(addrs[*count].addr.ifname));
++(*count);
}
break;
default:
;
}
close(s);
if_addr = if_addr->ifa_next;
}
*count = n;
_status = 0;
return _status;
_status=0;
abort:
if (if_addrs_head) {
freeifaddrs(if_addrs_head);
}
return(_status);
}
#endif
static int
@ -724,7 +347,7 @@ nr_stun_is_duplicate_addr(nr_local_addr addrs[], int count, nr_local_addr *addr)
}
int
nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback, int *count)
nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback, int remove_link_local, int *count)
{
int r, _status;
nr_local_addr *tmp = 0;
@ -743,6 +366,11 @@ nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback, int *
else if (remove_loopback && nr_transport_addr_is_loopback(&addrs[i].addr)) {
/* skip addrs[i], it's a loopback */
}
else if (remove_link_local &&
addrs[i].addr.ip_version == NR_IPV6 &&
nr_transport_addr_is_link_local(&addrs[i].addr)) {
/* skip addrs[i], it's a link-local address */
}
else {
/* otherwise, copy it to the temporary array */
if ((r=nr_local_addr_copy(&tmp[n], &addrs[i])))
@ -768,23 +396,19 @@ nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback, int *
#ifndef USE_PLATFORM_NR_STUN_GET_ADDRS
int
nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int drop_loopback, int *count)
nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int drop_loopback, int drop_link_local, int *count)
{
int _status=0;
int i;
char typestr[100];
#if defined(BSD) || defined(DARWIN)
_status = stun_get_mib_addrs(addrs, maxaddrs, count);
#elif defined(WIN32)
#ifdef WIN32
_status = stun_get_win32_addrs(addrs, maxaddrs, count);
#elif defined(__sparc__)
_status = stun_get_sparc_addrs(addrs, maxaddrs, count);
#else
_status = stun_get_siocgifconf_addrs(addrs, maxaddrs, count);
_status = stun_getifaddrs(addrs, maxaddrs, count);
#endif
nr_stun_remove_duplicate_addrs(addrs, drop_loopback, count);
nr_stun_remove_duplicate_addrs(addrs, drop_loopback, drop_link_local, count);
for (i = 0; i < *count; ++i) {
nr_local_addr_fmt_info_string(addrs+i,typestr,sizeof(typestr));

View File

@ -37,7 +37,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "transport_addr.h"
#include "local_addr.h"
int nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int remove_loopback, int *count);
int nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback,int *count);
int nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int remove_loopback, int remove_link_local, int *count);
int nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback, int remove_link_local, int *count);
#endif

View File

@ -0,0 +1,242 @@
/*
Copyright (c) 2011, The WebRTC project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Google nor the names of its contributors may
be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(ANDROID)
#include "ifaddrs-android.h"
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/utsname.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <unistd.h>
#include <errno.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
struct netlinkrequest {
struct nlmsghdr header;
struct ifaddrmsg msg;
};
static const int kMaxReadSize = 4096;
static int set_ifname(struct ifaddrs* ifaddr, int interface) {
char buf[IFNAMSIZ] = {0};
char* name = if_indextoname(interface, buf);
if (name == NULL) {
return -1;
}
ifaddr->ifa_name = malloc(strlen(name) + 1);
strncpy(ifaddr->ifa_name, name, strlen(name) + 1);
return 0;
}
static int set_flags(struct ifaddrs* ifaddr) {
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd == -1) {
return -1;
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ - 1);
int rc = ioctl(fd, SIOCGIFFLAGS, &ifr);
close(fd);
if (rc == -1) {
return -1;
}
ifaddr->ifa_flags = ifr.ifr_flags;
return 0;
}
static int set_addresses(struct ifaddrs* ifaddr, struct ifaddrmsg* msg, void* data,
size_t len) {
if (msg->ifa_family == AF_INET) {
struct sockaddr_in* sa = malloc(sizeof(struct sockaddr_in));
memset(sa, 0, sizeof(struct sockaddr_in));
sa->sin_family = AF_INET;
memcpy(&sa->sin_addr, data, len);
ifaddr->ifa_addr = (struct sockaddr*)sa;
} else if (msg->ifa_family == AF_INET6) {
struct sockaddr_in6* sa = malloc(sizeof(struct sockaddr_in6));
memset(sa, 0, sizeof(struct sockaddr_in6));
sa->sin6_family = AF_INET6;
sa->sin6_scope_id = msg->ifa_index;
memcpy(&sa->sin6_addr, data, len);
ifaddr->ifa_addr = (struct sockaddr*)sa;
} else {
return -1;
}
return 0;
}
static int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) {
char* prefix = NULL;
if (family == AF_INET) {
struct sockaddr_in* mask = malloc(sizeof(struct sockaddr_in));
memset(mask, 0, sizeof(struct sockaddr_in));
mask->sin_family = AF_INET;
memset(&mask->sin_addr, 0, sizeof(struct in_addr));
ifaddr->ifa_netmask = (struct sockaddr*)mask;
if (prefixlen > 32) {
prefixlen = 32;
}
prefix = (char*)&mask->sin_addr;
} else if (family == AF_INET6) {
struct sockaddr_in6* mask = malloc(sizeof(struct sockaddr_in6));
memset(mask, 0, sizeof(struct sockaddr_in6));
mask->sin6_family = AF_INET6;
memset(&mask->sin6_addr, 0, sizeof(struct in6_addr));
ifaddr->ifa_netmask = (struct sockaddr*)mask;
if (prefixlen > 128) {
prefixlen = 128;
}
prefix = (char*)&mask->sin6_addr;
} else {
return -1;
}
for (int i = 0; i < (prefixlen / 8); i++) {
*prefix++ = 0xFF;
}
char remainder = 0xff;
remainder <<= (8 - prefixlen % 8);
*prefix = remainder;
return 0;
}
static int populate_ifaddrs(struct ifaddrs* ifaddr, struct ifaddrmsg* msg, void* bytes,
size_t len) {
if (set_ifname(ifaddr, msg->ifa_index) != 0) {
return -1;
}
if (set_flags(ifaddr) != 0) {
return -1;
}
if (set_addresses(ifaddr, msg, bytes, len) != 0) {
return -1;
}
if (make_prefixes(ifaddr, msg->ifa_family, msg->ifa_prefixlen) != 0) {
return -1;
}
return 0;
}
int android_getifaddrs(struct ifaddrs** result) {
int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (fd < 0) {
return -1;
}
struct netlinkrequest ifaddr_request;
memset(&ifaddr_request, 0, sizeof(ifaddr_request));
ifaddr_request.header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
ifaddr_request.header.nlmsg_type = RTM_GETADDR;
ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
ssize_t count = send(fd, &ifaddr_request, ifaddr_request.header.nlmsg_len, 0);
if ((size_t)count != ifaddr_request.header.nlmsg_len) {
close(fd);
return -1;
}
struct ifaddrs* start = NULL;
struct ifaddrs* current = NULL;
char buf[kMaxReadSize];
ssize_t amount_read = recv(fd, &buf, kMaxReadSize, 0);
while (amount_read > 0) {
struct nlmsghdr* header = (struct nlmsghdr*)&buf[0];
size_t header_size = (size_t)amount_read;
for ( ; NLMSG_OK(header, header_size);
header = NLMSG_NEXT(header, header_size)) {
switch (header->nlmsg_type) {
case NLMSG_DONE:
/* Success. Return. */
*result = start;
close(fd);
return 0;
case NLMSG_ERROR:
close(fd);
android_freeifaddrs(start);
return -1;
case RTM_NEWADDR: {
struct ifaddrmsg* address_msg =
(struct ifaddrmsg*)NLMSG_DATA(header);
struct rtattr* rta = IFA_RTA(address_msg);
ssize_t payload_len = IFA_PAYLOAD(header);
while (RTA_OK(rta, payload_len)) {
if (rta->rta_type == IFA_ADDRESS) {
int family = address_msg->ifa_family;
if (family == AF_INET || family == AF_INET6) {
struct ifaddrs* newest = malloc(sizeof(struct ifaddrs));
memset(newest, 0, sizeof(struct ifaddrs));
if (current) {
current->ifa_next = newest;
} else {
start = newest;
}
if (populate_ifaddrs(newest, address_msg, RTA_DATA(rta),
RTA_PAYLOAD(rta)) != 0) {
android_freeifaddrs(start);
*result = NULL;
return -1;
}
current = newest;
}
}
rta = RTA_NEXT(rta, payload_len);
}
break;
}
}
}
amount_read = recv(fd, &buf, kMaxReadSize, 0);
}
close(fd);
android_freeifaddrs(start);
return -1;
}
void android_freeifaddrs(struct ifaddrs* addrs) {
struct ifaddrs* last = NULL;
struct ifaddrs* cursor = addrs;
while (cursor) {
free(cursor->ifa_name);
free(cursor->ifa_addr);
free(cursor->ifa_netmask);
last = cursor;
cursor = cursor->ifa_next;
free(last);
}
}
#endif /* defined(ANDROID) */

View File

@ -0,0 +1,57 @@
/*
Copyright (c) 2011, The WebRTC project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Google nor the names of its contributors may
be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef WEBRTC_BASE_IFADDRS_ANDROID_H_
#define WEBRTC_BASE_IFADDRS_ANDROID_H_
#include <stdio.h>
#include <sys/socket.h>
/* Implementation of getifaddrs for Android.
* Fills out a list of ifaddr structs (see below) which contain information
* about every network interface available on the host.
* See 'man getifaddrs' on Linux or OS X (nb: it is not a POSIX function). */
struct ifaddrs {
struct ifaddrs* ifa_next;
char* ifa_name;
unsigned int ifa_flags;
struct sockaddr* ifa_addr;
struct sockaddr* ifa_netmask;
/* Real ifaddrs has broadcast, point to point and data members.
* We don't need them (yet?). */
};
int android_getifaddrs(struct ifaddrs** result);
void android_freeifaddrs(struct ifaddrs* addrs);
#endif /* WEBRTC_BASE_IFADDRS_ANDROID_H_ */

View File

@ -446,9 +446,15 @@ nr_stun_attr_codec_addr_encode(nr_stun_attr_info *attr_info, void *data, int off
break;
case NR_IPV6:
assert(0);
ABORT(R_INTERNAL);
family = NR_STUN_IPV6_FAMILY;
if (nr_stun_encode_htons(20 , buflen, buf, &offset)
|| nr_stun_encode(&pad, 1 , buflen, buf, &offset)
|| nr_stun_encode(&family, 1 , buflen, buf, &offset)
|| nr_stun_encode_htons(ntohs(addr->u.addr6.sin6_port), buflen, buf, &offset)
|| nr_stun_encode(addr->u.addr6.sin6_addr.s6_addr, 16, buflen, buf, &offset))
ABORT(R_FAILED);
break;
default:
assert(0);
ABORT(R_INTERNAL);
@ -470,6 +476,7 @@ nr_stun_attr_codec_addr_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR
UCHAR family;
UINT2 port;
UINT4 addr4;
struct in6_addr addr6;
nr_transport_addr *result = data;
if (nr_stun_decode(1, buf, buflen, &offset, &pad)
@ -492,17 +499,17 @@ nr_stun_attr_codec_addr_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR
break;
case NR_STUN_IPV6_FAMILY:
if (attrlen != 16) {
if (attrlen != 20) {
r_log(NR_LOG_STUN, LOG_WARNING, "Illegal attribute length: %d", attrlen);
ABORT(R_FAILED);
}
r_log(NR_LOG_STUN, LOG_WARNING, "IPv6 not supported");
#ifdef NDEBUG
ABORT(SKIP_ATTRIBUTE_DECODE);
#else
UNIMPLEMENTED;
#endif /* NDEBUG */
if (nr_stun_decode_htons(buf, buflen, &offset, &port)
|| nr_stun_decode(16, buf, buflen, &offset, addr6.s6_addr))
ABORT(R_FAILED);
if (nr_ip6_port_to_transport_addr(&addr6, port, IPPROTO_UDP, result))
ABORT(R_FAILED);
break;
default:
@ -1094,7 +1101,7 @@ nr_stun_attr_codec_xor_mapped_address_encode(nr_stun_attr_info *attr_info, void
* message ID for this */
magic_cookie = ntohl(header->magic_cookie);
nr_stun_xor_mapped_address(magic_cookie, &xor_mapped_address->unmasked, &xor_mapped_address->masked);
nr_stun_xor_mapped_address(magic_cookie, header->id, &xor_mapped_address->unmasked, &xor_mapped_address->masked);
r_log(NR_LOG_STUN, LOG_DEBUG, "Masked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->masked.as_string);
@ -1123,7 +1130,7 @@ nr_stun_attr_codec_xor_mapped_address_decode(nr_stun_attr_info *attr_info, int a
* message ID for this */
magic_cookie = ntohl(header->magic_cookie);
nr_stun_xor_mapped_address(magic_cookie, &xor_mapped_address->masked, &xor_mapped_address->unmasked);
nr_stun_xor_mapped_address(magic_cookie, header->id, &xor_mapped_address->masked, &xor_mapped_address->unmasked);
r_log(NR_LOG_STUN, LOG_DEBUG, "Unmasked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->unmasked.as_string);

View File

@ -45,6 +45,7 @@ extern "C" {
#define NR_STUN_REG_PREF_CLNT_FINAL_RETRANSMIT_BACKOFF "stun.client.final_retransmit_backoff"
#define NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS "stun.allow_loopback"
#define NR_STUN_REG_PREF_ALLOW_LINK_LOCAL_ADDRS "stun.allow_link_local"
#define NR_STUN_REG_PREF_ADDRESS_PRFX "stun.address"
#define NR_STUN_REG_PREF_SERVER_NAME "stun.server.name"
#define NR_STUN_REG_PREF_SERVER_NONCE_SIZE "stun.server.nonce_size"

View File

@ -71,7 +71,7 @@ nr_stun_startup(void)
}
int
nr_stun_xor_mapped_address(UINT4 magicCookie, nr_transport_addr *from, nr_transport_addr *to)
nr_stun_xor_mapped_address(UINT4 magicCookie, UINT12 transactionId, nr_transport_addr *from, nr_transport_addr *to)
{
int _status;
@ -83,8 +83,26 @@ nr_stun_xor_mapped_address(UINT4 magicCookie, nr_transport_addr *from, nr_transp
from->protocol, to);
break;
case NR_IPV6:
assert(0);
ABORT(R_INTERNAL);
{
union {
unsigned char addr[16];
UINT4 addr32[4];
} maskedAddr;
maskedAddr.addr32[0] = htonl(magicCookie); /* Passed in host byte order */
memcpy(&maskedAddr.addr32[1], transactionId.octet, sizeof(transactionId));
/* We now have the mask in network byte order */
/* Xor the address in network byte order */
for (int i = 0; i < sizeof(maskedAddr); ++i) {
maskedAddr.addr[i] ^= from->u.addr6.sin6_addr.s6_addr[i];
}
nr_ip6_port_to_transport_addr(
(struct in6_addr*)&maskedAddr,
(ntohs(from->u.addr6.sin6_port) ^ (magicCookie>>16)),
from->protocol, to);
}
break;
default:
assert(0);
@ -111,6 +129,7 @@ nr_stun_find_local_addresses(nr_local_addr addrs[], int maxaddrs, int *count)
if (*count == 0) {
char allow_loopback;
char allow_link_local;
if ((r=NR_reg_get_char(NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, &allow_loopback))) {
if (r == R_NOT_FOUND)
@ -119,7 +138,14 @@ nr_stun_find_local_addresses(nr_local_addr addrs[], int maxaddrs, int *count)
ABORT(r);
}
if ((r=nr_stun_get_addrs(addrs, maxaddrs, !allow_loopback, count)))
if ((r=NR_reg_get_char(NR_STUN_REG_PREF_ALLOW_LINK_LOCAL_ADDRS, &allow_link_local))) {
if (r == R_NOT_FOUND)
allow_link_local = 0;
else
ABORT(r);
}
if ((r=nr_stun_get_addrs(addrs, maxaddrs, !allow_loopback, !allow_link_local, count)))
ABORT(r);
goto done;

View File

@ -42,7 +42,7 @@ extern int NR_LOG_STUN;
int nr_stun_startup(void);
int nr_stun_xor_mapped_address(UINT4 magicCookie, nr_transport_addr *from, nr_transport_addr *to);
int nr_stun_xor_mapped_address(UINT4 magicCookie, UINT12 transactionId, nr_transport_addr *from, nr_transport_addr *to);
int nr_stun_find_local_addresses(nr_local_addr addrs[], int maxaddrs, int *count);

View File

@ -724,6 +724,31 @@ inet_ntop6(const unsigned char *src, char *dst, size_t size)
}
#endif /* INET6 */
#ifdef WIN32
/* Not exactly, will forgive stuff like <addr>:<port> */
int inet_pton(int af, const char *src, void *dst)
{
struct sockaddr_storage ss;
int addrlen = sizeof(ss);
if (af != AF_INET && af != AF_INET6) {
return -1;
}
if (!WSAStringToAddressA(src, af, NULL, (struct sockaddr*)&ss, &addrlen)) {
if (af == AF_INET) {
struct sockaddr_in *in = (struct sockaddr_in*)&ss;
memcpy(dst, &in->sin_addr, sizeof(struct in_addr));
} else {
struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&ss;
memcpy(dst, &in6->sin6_addr, sizeof(struct in6_addr));
}
return 1;
}
return 0;
}
#endif /* WIN32 */
#endif
#ifdef WIN32

View File

@ -67,6 +67,7 @@ int nr_reg_uint8_fetch_and_check(NR_registry key, UINT8 min, UINT8 max, int log_
#ifdef WIN32
int snprintf(char *buffer, size_t n, const char *format, ...);
const char *inet_ntop(int af, const void *src, char *dst, size_t size);
int inet_pton(int af, const char *src, void *dst);
#endif
#endif

View File

@ -376,6 +376,7 @@ PeerConnectionImpl::PeerConnectionImpl(const GlobalObject* aGlobal)
, mPrivacyRequested(false)
, mSTSThread(nullptr)
, mAllowIceLoopback(false)
, mAllowIceLinkLocal(false)
, mMedia(nullptr)
, mUuidGen(MakeUnique<PCUuidGenerator>())
, mNumAudioStreams(0)
@ -397,6 +398,8 @@ PeerConnectionImpl::PeerConnectionImpl(const GlobalObject* aGlobal)
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
mAllowIceLoopback = Preferences::GetBool(
"media.peerconnection.ice.loopback", false);
mAllowIceLinkLocal = Preferences::GetBool(
"media.peerconnection.ice.link_local", false);
#endif
}
@ -732,7 +735,6 @@ PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver,
}
mMedia = new PeerConnectionMedia(this);
mMedia->SetAllowIceLoopback(mAllowIceLoopback);
// Connect ICE slots.
mMedia->SignalIceGatheringStateChange.connect(

View File

@ -287,6 +287,11 @@ public:
// Configure the ability to use localhost.
void SetAllowIceLoopback(bool val) { mAllowIceLoopback = val; }
bool GetAllowIceLoopback() const { return mAllowIceLoopback; }
// Configure the ability to use IPV6 link-local addresses.
void SetAllowIceLinkLocal(bool val) { mAllowIceLinkLocal = val; }
bool GetAllowIceLinkLocal() const { return mAllowIceLinkLocal; }
// Handle system to allow weak references to be passed through C code
virtual const std::string& GetHandle();
@ -739,6 +744,7 @@ private:
#endif
bool mAllowIceLoopback;
bool mAllowIceLinkLocal;
nsRefPtr<PeerConnectionMedia> mMedia;
// The JSEP negotiation session.

View File

@ -219,7 +219,6 @@ PeerConnectionMedia::PeerConnectionMedia(PeerConnectionImpl *parent)
: mParent(parent),
mParentHandle(parent->GetHandle()),
mParentName(parent->GetName()),
mAllowIceLoopback(false),
mIceCtx(nullptr),
mDNSResolver(new NrIceResolver()),
mUuidGen(MakeUnique<PCUuidGenerator>()),
@ -311,8 +310,9 @@ nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_serv
mIceCtx = NrIceCtx::Create("PC:" + mParentName,
true, // Offerer
true, // Explicitly set priorities
mAllowIceLoopback,
ice_tcp);
mParent->GetAllowIceLoopback(),
ice_tcp,
mParent->GetAllowIceLinkLocal());
if(!mIceCtx) {
CSFLogError(logTag, "%s: Failed to create Ice Context", __FUNCTION__);
return NS_ERROR_FAILURE;

View File

@ -232,9 +232,6 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
// WARNING: This destroys the object!
void SelfDestruct();
// Configure the ability to use localhost.
void SetAllowIceLoopback(bool val) { mAllowIceLoopback = val; }
RefPtr<NrIceCtx> ice_ctx() const { return mIceCtx; }
RefPtr<NrIceMediaStream> ice_media_stream(size_t i) const {
@ -491,9 +488,6 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
std::map<size_t, std::pair<bool, RefPtr<MediaSessionConduit>>> mConduits;
// Allow loopback for ICE.
bool mAllowIceLoopback;
// ICE objects
RefPtr<NrIceCtx> mIceCtx;

View File

@ -286,6 +286,11 @@ public:
SetAddress(const std::string& address)
{
mAddr = address;
if (mAddr.find(':') != std::string::npos) {
mAddrType = sdp::kIPv6;
} else {
mAddrType = sdp::kIPv4;
}
}
uint8_t
GetTtl() const

View File

@ -913,6 +913,7 @@ class SignalingAgent {
PeerConnectionImpl::CreatePeerConnection();
EXPECT_TRUE(pcImpl);
pcImpl->SetAllowIceLoopback(true);
pcImpl->SetAllowIceLinkLocal(true);
pc = new PCDispatchWrapper(pcImpl);
}
@ -4709,7 +4710,7 @@ int main(int argc, char **argv) {
// Adds a listener to the end. Google Test takes the ownership.
listeners.Append(new test::RingbufferDumper(test_utils));
test_utils->sts_target()->Dispatch(
WrapRunnableNM(&TestStunServer::GetInstance), NS_DISPATCH_SYNC);
WrapRunnableNM(&TestStunServer::GetInstance, AF_INET), NS_DISPATCH_SYNC);
// Set the main thread global which is this thread.
nsIThread *thread;

View File

@ -375,6 +375,7 @@ pref("media.navigator.permission.disabled", false);
pref("media.peerconnection.default_iceservers", "[]");
pref("media.peerconnection.ice.loopback", false); // Set only for testing in offline environments.
pref("media.peerconnection.ice.tcp", false);
pref("media.peerconnection.ice.link_local", false); // Set only for testing IPV6 in networks that don't assign IPV6 addresses
pref("media.peerconnection.use_document_iceservers", true);
pref("media.peerconnection.identity.enabled", true);
pref("media.peerconnection.identity.timeout", 10000);