Add new Stun utility functions
This patch introduces 3 new functions on StunMessages - Clone, copy a message - IsStunMethod, verifies that a buffer is a StunMessage w/o requring a fingerprint - EqualAttributes, compare attributes in two stun messages (with filter) This methods will be used to implement GOOG_PING BUG=webrtc:11100 Change-Id: I284726c74aa0437be0bb9fbcf943c7d64a18acec Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/160281 Commit-Queue: Jonas Oreland <jonaso@webrtc.org> Reviewed-by: Björn Terelius <terelius@webrtc.org> Cr-Commit-Position: refs/heads/master@{#29950}
This commit is contained in:
committed by
Commit Bot
parent
2dec496f80
commit
253d50fbe6
@ -370,6 +370,28 @@ bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
|
|||||||
rtc::ComputeCrc32(data, size - fingerprint_attr_size));
|
rtc::ComputeCrc32(data, size - fingerprint_attr_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool StunMessage::IsStunMethod(rtc::ArrayView<int> methods,
|
||||||
|
const char* data,
|
||||||
|
size_t size) {
|
||||||
|
// Check the message length.
|
||||||
|
if (size % 4 != 0 || size < kStunHeaderSize)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Skip the rest if the magic cookie isn't present.
|
||||||
|
const char* magic_cookie =
|
||||||
|
data + kStunTransactionIdOffset - kStunMagicCookieLength;
|
||||||
|
if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int method = rtc::GetBE16(data);
|
||||||
|
for (int m : methods) {
|
||||||
|
if (m == method) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool StunMessage::AddFingerprint() {
|
bool StunMessage::AddFingerprint() {
|
||||||
// Add the attribute with a dummy value. Since this is a known attribute,
|
// Add the attribute with a dummy value. Since this is a known attribute,
|
||||||
// it can't fail.
|
// it can't fail.
|
||||||
@ -557,6 +579,44 @@ bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
|
|||||||
transaction_id.size() == kStunLegacyTransactionIdLength;
|
transaction_id.size() == kStunLegacyTransactionIdLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool StunMessage::EqualAttributes(
|
||||||
|
const StunMessage* other,
|
||||||
|
std::function<bool(int type)> attribute_type_mask) const {
|
||||||
|
RTC_DCHECK(other != nullptr);
|
||||||
|
rtc::ByteBufferWriter tmp_buffer_ptr1;
|
||||||
|
rtc::ByteBufferWriter tmp_buffer_ptr2;
|
||||||
|
for (const auto& attr : attrs_) {
|
||||||
|
if (attribute_type_mask(attr->type())) {
|
||||||
|
const StunAttribute* other_attr = other->GetAttribute(attr->type());
|
||||||
|
if (other_attr == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
tmp_buffer_ptr1.Clear();
|
||||||
|
tmp_buffer_ptr2.Clear();
|
||||||
|
attr->Write(&tmp_buffer_ptr1);
|
||||||
|
other_attr->Write(&tmp_buffer_ptr2);
|
||||||
|
if (tmp_buffer_ptr1.Length() != tmp_buffer_ptr2.Length()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (memcmp(tmp_buffer_ptr1.Data(), tmp_buffer_ptr2.Data(),
|
||||||
|
tmp_buffer_ptr1.Length()) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& attr : other->attrs_) {
|
||||||
|
if (attribute_type_mask(attr->type())) {
|
||||||
|
const StunAttribute* own_attr = GetAttribute(attr->type());
|
||||||
|
if (own_attr == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// we have already compared all values...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// StunAttribute
|
// StunAttribute
|
||||||
|
|
||||||
StunAttribute::StunAttribute(uint16_t type, uint16_t length)
|
StunAttribute::StunAttribute(uint16_t type, uint16_t length)
|
||||||
@ -1205,4 +1265,20 @@ StunMessage* IceMessage::CreateNew() const {
|
|||||||
return new IceMessage();
|
return new IceMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<StunMessage> StunMessage::Clone() const {
|
||||||
|
std::unique_ptr<StunMessage> copy(CreateNew());
|
||||||
|
if (!copy) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
rtc::ByteBufferWriter buf;
|
||||||
|
if (!Write(&buf)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
rtc::ByteBufferReader reader(buf);
|
||||||
|
if (!copy->Read(&reader)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace cricket
|
} // namespace cricket
|
||||||
|
|||||||
@ -202,6 +202,12 @@ class StunMessage {
|
|||||||
// current message.
|
// current message.
|
||||||
bool AddMessageIntegrity32(absl::string_view password);
|
bool AddMessageIntegrity32(absl::string_view password);
|
||||||
|
|
||||||
|
// Verify that a buffer has stun magic cookie and one of the specified
|
||||||
|
// methods. Note that it does not check for the existance of FINGERPRINT.
|
||||||
|
static bool IsStunMethod(rtc::ArrayView<int> methods,
|
||||||
|
const char* data,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
// Verifies that a given buffer is STUN by checking for a correct FINGERPRINT.
|
// Verifies that a given buffer is STUN by checking for a correct FINGERPRINT.
|
||||||
static bool ValidateFingerprint(const char* data, size_t size);
|
static bool ValidateFingerprint(const char* data, size_t size);
|
||||||
|
|
||||||
@ -223,10 +229,20 @@ class StunMessage {
|
|||||||
// This is used for testing.
|
// This is used for testing.
|
||||||
void SetStunMagicCookie(uint32_t val);
|
void SetStunMagicCookie(uint32_t val);
|
||||||
|
|
||||||
|
// Contruct a copy of |this|.
|
||||||
|
std::unique_ptr<StunMessage> Clone() const;
|
||||||
|
|
||||||
|
// Check if the attributes of this StunMessage equals those of |other|
|
||||||
|
// for all attributes that |attribute_type_mask| return true
|
||||||
|
bool EqualAttributes(const StunMessage* other,
|
||||||
|
std::function<bool(int type)> attribute_type_mask) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Verifies that the given attribute is allowed for this message.
|
// Verifies that the given attribute is allowed for this message.
|
||||||
virtual StunAttributeValueType GetAttributeValueType(int type) const;
|
virtual StunAttributeValueType GetAttributeValueType(int type) const;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<StunAttribute>> attrs_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StunAttribute* CreateAttribute(int type, size_t length) /* const*/;
|
StunAttribute* CreateAttribute(int type, size_t length) /* const*/;
|
||||||
const StunAttribute* GetAttribute(int type) const;
|
const StunAttribute* GetAttribute(int type) const;
|
||||||
@ -245,7 +261,6 @@ class StunMessage {
|
|||||||
uint16_t length_;
|
uint16_t length_;
|
||||||
std::string transaction_id_;
|
std::string transaction_id_;
|
||||||
uint32_t reduced_transaction_id_;
|
uint32_t reduced_transaction_id_;
|
||||||
std::vector<std::unique_ptr<StunAttribute>> attrs_;
|
|
||||||
uint32_t stun_magic_cookie_;
|
uint32_t stun_magic_cookie_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1751,6 +1751,109 @@ TEST_F(StunTest, CopyAttribute) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test Clone
|
||||||
|
TEST_F(StunTest, Clone) {
|
||||||
|
IceMessage msg;
|
||||||
|
{
|
||||||
|
auto errorcode = StunAttribute::CreateErrorCode();
|
||||||
|
errorcode->SetCode(kTestErrorCode);
|
||||||
|
errorcode->SetReason(kTestErrorReason);
|
||||||
|
msg.AddAttribute(std::move(errorcode));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto bytes2 = StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
|
||||||
|
bytes2->CopyBytes("abcdefghijkl");
|
||||||
|
msg.AddAttribute(std::move(bytes2));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto uval2 = StunAttribute::CreateUInt32(STUN_ATTR_RETRANSMIT_COUNT);
|
||||||
|
uval2->SetValue(11);
|
||||||
|
msg.AddAttribute(std::move(uval2));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto addr = StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
|
||||||
|
addr->SetIP(rtc::IPAddress(kIPv6TestAddress1));
|
||||||
|
addr->SetPort(kTestMessagePort1);
|
||||||
|
msg.AddAttribute(std::move(addr));
|
||||||
|
}
|
||||||
|
auto copy = msg.Clone();
|
||||||
|
ASSERT_NE(nullptr, copy.get());
|
||||||
|
|
||||||
|
msg.SetTransactionID("0123456789ab");
|
||||||
|
copy->SetTransactionID("0123456789ab");
|
||||||
|
|
||||||
|
rtc::ByteBufferWriter out1;
|
||||||
|
EXPECT_TRUE(msg.Write(&out1));
|
||||||
|
rtc::ByteBufferWriter out2;
|
||||||
|
EXPECT_TRUE(copy->Write(&out2));
|
||||||
|
|
||||||
|
ASSERT_EQ(out1.Length(), out2.Length());
|
||||||
|
EXPECT_EQ(0, memcmp(out1.Data(), out2.Data(), out1.Length()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test EqualAttributes
|
||||||
|
TEST_F(StunTest, EqualAttributes) {
|
||||||
|
IceMessage msg;
|
||||||
|
{
|
||||||
|
auto errorcode = StunAttribute::CreateErrorCode();
|
||||||
|
errorcode->SetCode(kTestErrorCode);
|
||||||
|
errorcode->SetReason(kTestErrorReason);
|
||||||
|
msg.AddAttribute(std::move(errorcode));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto bytes2 = StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
|
||||||
|
bytes2->CopyBytes("abcdefghijkl");
|
||||||
|
msg.AddAttribute(std::move(bytes2));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto uval2 = StunAttribute::CreateUInt32(STUN_ATTR_RETRANSMIT_COUNT);
|
||||||
|
uval2->SetValue(11);
|
||||||
|
msg.AddAttribute(std::move(uval2));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto addr = StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
|
||||||
|
addr->SetIP(rtc::IPAddress(kIPv6TestAddress1));
|
||||||
|
addr->SetPort(kTestMessagePort1);
|
||||||
|
msg.AddAttribute(std::move(addr));
|
||||||
|
}
|
||||||
|
auto copy = msg.Clone();
|
||||||
|
ASSERT_NE(nullptr, copy.get());
|
||||||
|
|
||||||
|
EXPECT_TRUE(copy->EqualAttributes(&msg, [](int type) { return true; }));
|
||||||
|
|
||||||
|
{
|
||||||
|
auto attr = StunAttribute::CreateByteString(STUN_ATTR_NONCE);
|
||||||
|
attr->CopyBytes("keso");
|
||||||
|
msg.AddAttribute(std::move(attr));
|
||||||
|
EXPECT_FALSE(copy->EqualAttributes(&msg, [](int type) { return true; }));
|
||||||
|
EXPECT_TRUE(copy->EqualAttributes(
|
||||||
|
&msg, [](int type) { return type != STUN_ATTR_NONCE; }));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto attr = StunAttribute::CreateByteString(STUN_ATTR_NONCE);
|
||||||
|
attr->CopyBytes("keso");
|
||||||
|
copy->AddAttribute(std::move(attr));
|
||||||
|
EXPECT_TRUE(copy->EqualAttributes(&msg, [](int type) { return true; }));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
copy->RemoveAttribute(STUN_ATTR_NONCE);
|
||||||
|
auto attr = StunAttribute::CreateByteString(STUN_ATTR_NONCE);
|
||||||
|
attr->CopyBytes("kent");
|
||||||
|
copy->AddAttribute(std::move(attr));
|
||||||
|
EXPECT_FALSE(copy->EqualAttributes(&msg, [](int type) { return true; }));
|
||||||
|
EXPECT_TRUE(copy->EqualAttributes(
|
||||||
|
&msg, [](int type) { return type != STUN_ATTR_NONCE; }));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
msg.RemoveAttribute(STUN_ATTR_NONCE);
|
||||||
|
EXPECT_FALSE(copy->EqualAttributes(&msg, [](int type) { return true; }));
|
||||||
|
EXPECT_TRUE(copy->EqualAttributes(
|
||||||
|
&msg, [](int type) { return type != STUN_ATTR_NONCE; }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(StunTest, ReduceTransactionIdIsHostOrderIndependent) {
|
TEST_F(StunTest, ReduceTransactionIdIsHostOrderIndependent) {
|
||||||
std::string transaction_id = "abcdefghijkl";
|
std::string transaction_id = "abcdefghijkl";
|
||||||
StunMessage message;
|
StunMessage message;
|
||||||
@ -1793,4 +1896,11 @@ TEST_F(StunTest, GoogMiscInfo) {
|
|||||||
EXPECT_EQ(0xAB0CU, types->GetType(2));
|
EXPECT_EQ(0xAB0CU, types->GetType(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(StunTest, IsStunMethod) {
|
||||||
|
int methods[] = {STUN_BINDING_REQUEST};
|
||||||
|
EXPECT_TRUE(StunMessage::IsStunMethod(
|
||||||
|
methods, reinterpret_cast<const char*>(kRfc5769SampleRequest),
|
||||||
|
sizeof(kRfc5769SampleRequest)));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace cricket
|
} // namespace cricket
|
||||||
|
|||||||
Reference in New Issue
Block a user