Reset TURN port NONCE when a new socket is created.
For example, when the TURN port has an ALLOCATE_MISMATCH error.
BUG=webrtc:5432
Review URL: https://codereview.webrtc.org/1595613004
Cr-Original-Commit-Position: refs/heads/master@{#11453}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: c463e20069c670594117a44755805ac0989cc137
diff --git a/p2p/base/turnport.cc b/p2p/base/turnport.cc
index 4f5fef1..9fa549f 100644
--- a/p2p/base/turnport.cc
+++ b/p2p/base/turnport.cc
@@ -433,6 +433,7 @@
}
socket_ = NULL;
+ ResetNonce();
PrepareAddress();
++allocate_mismatch_retries_;
}
@@ -933,6 +934,12 @@
return true;
}
+void TurnPort::ResetNonce() {
+ hash_.clear();
+ nonce_.clear();
+ realm_.clear();
+}
+
static bool MatchesIP(TurnEntry* e, rtc::IPAddress ipaddr) {
return e->address().ipaddr() == ipaddr;
}
diff --git a/p2p/base/turnport.h b/p2p/base/turnport.h
index 9faf064..da14945 100644
--- a/p2p/base/turnport.h
+++ b/p2p/base/turnport.h
@@ -233,6 +233,7 @@
const rtc::PacketOptions& options);
void UpdateHash();
bool UpdateNonce(StunMessage* response);
+ void ResetNonce();
bool HasPermission(const rtc::IPAddress& ipaddr) const;
TurnEntry* FindEntry(const rtc::SocketAddress& address) const;
diff --git a/p2p/base/turnport_unittest.cc b/p2p/base/turnport_unittest.cc
index a503c2b..7649b5a 100644
--- a/p2p/base/turnport_unittest.cc
+++ b/p2p/base/turnport_unittest.cc
@@ -605,6 +605,39 @@
ASSERT_EQ(0U, turn_port_->Candidates().size());
}
+// Tests that TURN port nonce will be reset when receiving an ALLOCATE MISMATCH
+// error.
+TEST_F(TurnPortTest, TestTurnAllocateNonceResetAfterAllocateMismatch) {
+ // Do a normal allocation first.
+ CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
+ turn_port_->PrepareAddress();
+ EXPECT_TRUE_WAIT(turn_ready_, kTimeout);
+ rtc::SocketAddress first_addr(turn_port_->socket()->GetLocalAddress());
+ // Destroy the turnport while keeping the drop probability to 1 to
+ // suppress the release of the allocation at the server.
+ ss_->set_drop_probability(1.0);
+ turn_port_.reset();
+ rtc::Thread::Current()->ProcessMessages(0);
+ ss_->set_drop_probability(0.0);
+
+ // Force the socket server to assign the same port.
+ ss_->SetNextPortForTesting(first_addr.port());
+ turn_ready_ = false;
+ CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
+
+ // It is expected that the turn port will first get a nonce from the server
+ // using timestamp |ts_before| but then get an allocate mismatch error and
+ // receive an even newer nonce based on the system clock. |ts_before| is
+ // chosen so that the two NONCEs generated by the server will be different.
+ uint32_t ts_before = rtc::Time() - 1;
+ std::string first_nonce =
+ turn_server_.server()->SetTimestampForNextNonce(ts_before);
+ turn_port_->PrepareAddress();
+
+ EXPECT_TRUE_WAIT(turn_ready_, kTimeout);
+ EXPECT_NE(first_nonce, turn_port_->nonce());
+}
+
// Tests that a new local address is created after
// STUN_ERROR_ALLOCATION_MISMATCH.
TEST_F(TurnPortTest, TestTurnAllocateMismatch) {
diff --git a/p2p/base/turnserver.cc b/p2p/base/turnserver.cc
index 1502cdd..4754574 100644
--- a/p2p/base/turnserver.cc
+++ b/p2p/base/turnserver.cc
@@ -392,9 +392,8 @@
}
}
-std::string TurnServer::GenerateNonce() const {
+std::string TurnServer::GenerateNonce(uint32_t now) const {
// Generate a nonce of the form hex(now + HMAC-MD5(nonce_key_, now))
- uint32_t now = rtc::Time();
std::string input(reinterpret_cast<const char*>(&now), sizeof(now));
std::string nonce = rtc::hex_encode(input.c_str(), input.size());
nonce += rtc::ComputeHmac(rtc::DIGEST_MD5, nonce_key_, input);
@@ -464,8 +463,14 @@
int code, const std::string& reason) {
TurnMessage resp;
InitErrorResponse(msg, code, reason, &resp);
- VERIFY(resp.AddAttribute(new StunByteStringAttribute(
- STUN_ATTR_NONCE, GenerateNonce())));
+
+ uint32_t timestamp = rtc::Time();
+ if (ts_for_next_nonce_) {
+ timestamp = ts_for_next_nonce_;
+ ts_for_next_nonce_ = 0;
+ }
+ VERIFY(resp.AddAttribute(
+ new StunByteStringAttribute(STUN_ATTR_NONCE, GenerateNonce(timestamp))));
VERIFY(resp.AddAttribute(new StunByteStringAttribute(
STUN_ATTR_REALM, realm_)));
SendStun(conn, &resp);
diff --git a/p2p/base/turnserver.h b/p2p/base/turnserver.h
index 113bd4c..44a8b38 100644
--- a/p2p/base/turnserver.h
+++ b/p2p/base/turnserver.h
@@ -199,8 +199,14 @@
// Specifies the factory to use for creating external sockets.
void SetExternalSocketFactory(rtc::PacketSocketFactory* factory,
const rtc::SocketAddress& address);
+ // For testing only.
+ std::string SetTimestampForNextNonce(uint32_t timestamp) {
+ ts_for_next_nonce_ = timestamp;
+ return GenerateNonce(timestamp);
+ }
private:
+ std::string GenerateNonce(uint32_t now) const;
void OnInternalPacket(rtc::AsyncPacketSocket* socket, const char* data,
size_t size, const rtc::SocketAddress& address,
const rtc::PacketTime& packet_time);
@@ -221,7 +227,6 @@
bool CheckAuthorization(TurnServerConnection* conn, const StunMessage* msg,
const char* data, size_t size,
const std::string& key);
- std::string GenerateNonce() const;
bool ValidateNonce(const std::string& nonce) const;
TurnServerAllocation* FindAllocation(TurnServerConnection* conn);
@@ -270,6 +275,10 @@
AllocationMap allocations_;
+ // For testing only. If this is non-zero, the next NONCE will be generated
+ // from this value, and it will be reset to 0 after generating the NONCE.
+ uint32_t ts_for_next_nonce_ = 0;
+
friend class TurnServerAllocation;
};