From f4ae6dc76382309469049dab3b40465289dfa27a Mon Sep 17 00:00:00 2001 From: Honghai Zhang Date: Wed, 22 Jun 2016 22:34:58 -0700 Subject: [PATCH] Fix an issue in IPv6 support. When creating connections on turn port, check whether the local and remote candidates have the same IP address family, instead of checking the address family of the local socket against the remote candidate. BUG=5871 R=deadbeef@webrtc.org, pthatcher@webrtc.org Review URL: https://codereview.webrtc.org/2083803002 . Cr-Commit-Position: refs/heads/master@{#13269} --- webrtc/p2p/base/turnport.cc | 24 +++++++++---------- webrtc/p2p/base/turnport_unittest.cc | 36 +++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 15 deletions(-) diff --git a/webrtc/p2p/base/turnport.cc b/webrtc/p2p/base/turnport.cc index 40368110e3..824a25e644 100644 --- a/webrtc/p2p/base/turnport.cc +++ b/webrtc/p2p/base/turnport.cc @@ -291,7 +291,7 @@ void TurnPort::PrepareAddress() { if (!IsCompatibleAddress(server_address_.address)) { LOG(LS_ERROR) << "IP address family does not match: " << "server: " << server_address_.address.family() - << "local: " << ip().family(); + << " local: " << ip().family(); OnAllocateError(); return; } @@ -438,14 +438,10 @@ void TurnPort::OnAllocateMismatch() { ++allocate_mismatch_retries_; } -Connection* TurnPort::CreateConnection(const Candidate& address, +Connection* TurnPort::CreateConnection(const Candidate& remote_candidate, CandidateOrigin origin) { // TURN-UDP can only connect to UDP candidates. - if (!SupportsProtocol(address.protocol())) { - return NULL; - } - - if (!IsCompatibleAddress(address.address())) { + if (!SupportsProtocol(remote_candidate.protocol())) { return NULL; } @@ -453,15 +449,19 @@ Connection* TurnPort::CreateConnection(const Candidate& address, return NULL; } - // Create an entry, if needed, so we can get our permissions set up correctly. - CreateOrRefreshEntry(address.address()); - // A TURN port will have two candiates, STUN and TURN. STUN may not // present in all cases. If present stun candidate will be added first // and TURN candidate later. for (size_t index = 0; index < Candidates().size(); ++index) { - if (Candidates()[index].type() == RELAY_PORT_TYPE) { - ProxyConnection* conn = new ProxyConnection(this, index, address); + const Candidate& local_candidate = Candidates()[index]; + if (local_candidate.type() == RELAY_PORT_TYPE && + local_candidate.address().family() == + remote_candidate.address().family()) { + // Create an entry, if needed, so we can get our permissions set up + // correctly. + CreateOrRefreshEntry(remote_candidate.address()); + ProxyConnection* conn = + new ProxyConnection(this, index, remote_candidate); AddOrReplaceConnection(conn); return conn; } diff --git a/webrtc/p2p/base/turnport_unittest.cc b/webrtc/p2p/base/turnport_unittest.cc index d6d75aad09..2fa5525718 100644 --- a/webrtc/p2p/base/turnport_unittest.cc +++ b/webrtc/p2p/base/turnport_unittest.cc @@ -44,6 +44,8 @@ static const SocketAddress kLocalAddr1("11.11.11.11", 0); static const SocketAddress kLocalAddr2("22.22.22.22", 0); static const SocketAddress kLocalIPv6Addr( "2401:fa00:4:1000:be30:5bff:fee5:c3", 0); +static const SocketAddress kLocalIPv6Addr2( + "2401:fa00:4:2000:be30:5bff:fee5:d4", 0); static const SocketAddress kTurnUdpIntAddr("99.99.99.3", cricket::TURN_SERVER_PORT); static const SocketAddress kTurnTcpIntAddr("99.99.99.4", @@ -58,9 +60,8 @@ static const SocketAddress kTurnIPv6IntAddr( cricket::TURN_SERVER_PORT); static const SocketAddress kTurnUdpIPv6IntAddr( "2400:4030:1:2c00:be30:abcd:efab:cdef", cricket::TURN_SERVER_PORT); -static const SocketAddress kTurnUdpIPv6ExtAddr( - "2620:0:1000:1b03:2e41:38ff:fea6:f2a4", 0); +static const char kCandidateFoundation[] = "foundation"; static const char kIceUfrag1[] = "TESTICEUFRAG0001"; static const char kIceUfrag2[] = "TESTICEUFRAG0002"; static const char kIcePwd1[] = "TESTICEPWD00000000000001"; @@ -596,7 +597,7 @@ TEST_F(TurnPortTest, DISABLED_TestTurnTcpOnAddressResolveFailure) { // In case of UDP on address resolve failure, TurnPort will not create socket // and return allocate failure. -TEST_F(TurnPortTest, DISABLED_TestTurnUdpOnAdressResolveFailure) { +TEST_F(TurnPortTest, DISABLED_TestTurnUdpOnAddressResolveFailure) { CreateTurnPort(kTurnUsername, kTurnPassword, cricket::ProtocolAddress( rtc::SocketAddress("www.webrtc-blah-blah.com", 3478), cricket::PROTO_UDP)); @@ -1014,6 +1015,35 @@ TEST_F(TurnPortTest, TestTurnLocalIPv6AddressServerIPv6ExtenalIPv4) { EXPECT_NE(0, turn_port_->Candidates()[0].address().port()); } +// Tests that the local and remote candidate address families should match when +// a connection is created. Specifically, if a TURN port has an IPv6 address, +// its local candidate will still be an IPv4 address and it can only create +// connections with IPv4 remote candidates. +TEST_F(TurnPortTest, TestCandidateAddressFamilyMatch) { + turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, cricket::PROTO_UDP); + + CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword, + kTurnUdpIPv6ProtoAddr); + turn_port_->PrepareAddress(); + EXPECT_TRUE_WAIT(turn_ready_, kTimeout); + ASSERT_EQ(1U, turn_port_->Candidates().size()); + + // Create an IPv4 candidate. It will match the TURN candidate. + cricket::Candidate remote_candidate(cricket::ICE_CANDIDATE_COMPONENT_RTP, + "udp", kLocalAddr2, 0, "", "", "local", 0, + kCandidateFoundation); + remote_candidate.set_address(kLocalAddr2); + Connection* conn = + turn_port_->CreateConnection(remote_candidate, Port::ORIGIN_MESSAGE); + EXPECT_NE(nullptr, conn); + + // Set the candidate address family to IPv6. It won't match the TURN + // candidate. + remote_candidate.set_address(kLocalIPv6Addr2); + conn = turn_port_->CreateConnection(remote_candidate, Port::ORIGIN_MESSAGE); + EXPECT_EQ(nullptr, conn); +} + TEST_F(TurnPortTest, TestOriginHeader) { CreateTurnPortWithOrigin(kLocalAddr1, kTurnUsername, kTurnPassword, kTurnUdpProtoAddr, kTestOrigin);