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-Commit-Position: refs/heads/master@{#11453}
This commit is contained in:
honghaiz 2016-02-01 15:19:08 -08:00 committed by Commit bot
parent 94291480b6
commit c463e20069
5 changed files with 60 additions and 5 deletions

View File

@ -433,6 +433,7 @@ void TurnPort::OnAllocateMismatch() {
}
socket_ = NULL;
ResetNonce();
PrepareAddress();
++allocate_mismatch_retries_;
}
@ -933,6 +934,12 @@ bool TurnPort::UpdateNonce(StunMessage* response) {
return true;
}
void TurnPort::ResetNonce() {
hash_.clear();
nonce_.clear();
realm_.clear();
}
static bool MatchesIP(TurnEntry* e, rtc::IPAddress ipaddr) {
return e->address().ipaddr() == ipaddr;
}

View File

@ -233,6 +233,7 @@ class TurnPort : public Port {
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;

View File

@ -605,6 +605,39 @@ TEST_F(TurnPortTest, TestTurnAllocateBadPassword) {
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) {

View File

@ -392,9 +392,8 @@ void TurnServer::HandleAllocateRequest(TurnServerConnection* conn,
}
}
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 @@ void TurnServer::SendErrorResponseWithRealmAndNonce(
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);

View File

@ -199,8 +199,14 @@ class TurnServer : public sigslot::has_slots<> {
// 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 @@ class TurnServer : public sigslot::has_slots<> {
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 @@ class TurnServer : public sigslot::has_slots<> {
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;
};