xref: /aosp_15_r20/external/webrtc/api/transport/stun.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "api/transport/stun.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <string.h>
14*d9f75844SAndroid Build Coastguard Worker 
15*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
16*d9f75844SAndroid Build Coastguard Worker #include <cstdint>
17*d9f75844SAndroid Build Coastguard Worker #include <iterator>
18*d9f75844SAndroid Build Coastguard Worker #include <memory>
19*d9f75844SAndroid Build Coastguard Worker #include <utility>
20*d9f75844SAndroid Build Coastguard Worker 
21*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/byte_order.h"
22*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
23*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/crc32.h"
24*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/helpers.h"
25*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
26*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/message_digest.h"
27*d9f75844SAndroid Build Coastguard Worker #include "system_wrappers/include/metrics.h"
28*d9f75844SAndroid Build Coastguard Worker 
29*d9f75844SAndroid Build Coastguard Worker using rtc::ByteBufferReader;
30*d9f75844SAndroid Build Coastguard Worker using rtc::ByteBufferWriter;
31*d9f75844SAndroid Build Coastguard Worker 
32*d9f75844SAndroid Build Coastguard Worker namespace cricket {
33*d9f75844SAndroid Build Coastguard Worker 
34*d9f75844SAndroid Build Coastguard Worker namespace {
35*d9f75844SAndroid Build Coastguard Worker 
36*d9f75844SAndroid Build Coastguard Worker const int k127Utf8CharactersLengthInBytes = 508;
37*d9f75844SAndroid Build Coastguard Worker const int kMessageIntegrityAttributeLength = 20;
38*d9f75844SAndroid Build Coastguard Worker const int kTheoreticalMaximumAttributeLength = 65535;
39*d9f75844SAndroid Build Coastguard Worker 
ReduceTransactionId(absl::string_view transaction_id)40*d9f75844SAndroid Build Coastguard Worker uint32_t ReduceTransactionId(absl::string_view transaction_id) {
41*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(transaction_id.length() == cricket::kStunTransactionIdLength ||
42*d9f75844SAndroid Build Coastguard Worker              transaction_id.length() == cricket::kStunLegacyTransactionIdLength)
43*d9f75844SAndroid Build Coastguard Worker       << transaction_id.length();
44*d9f75844SAndroid Build Coastguard Worker   ByteBufferReader reader(transaction_id.data(), transaction_id.size());
45*d9f75844SAndroid Build Coastguard Worker   uint32_t result = 0;
46*d9f75844SAndroid Build Coastguard Worker   uint32_t next;
47*d9f75844SAndroid Build Coastguard Worker   while (reader.ReadUInt32(&next)) {
48*d9f75844SAndroid Build Coastguard Worker     result ^= next;
49*d9f75844SAndroid Build Coastguard Worker   }
50*d9f75844SAndroid Build Coastguard Worker   return result;
51*d9f75844SAndroid Build Coastguard Worker }
52*d9f75844SAndroid Build Coastguard Worker 
53*d9f75844SAndroid Build Coastguard Worker // Check the maximum length of a BYTE_STRING attribute against specifications.
LengthValid(int type,int length)54*d9f75844SAndroid Build Coastguard Worker bool LengthValid(int type, int length) {
55*d9f75844SAndroid Build Coastguard Worker   // "Less than 509 bytes" is intended to indicate a maximum of 127
56*d9f75844SAndroid Build Coastguard Worker   // UTF-8 characters, which may take up to 4 bytes per character.
57*d9f75844SAndroid Build Coastguard Worker   switch (type) {
58*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_USERNAME:
59*d9f75844SAndroid Build Coastguard Worker       return length <=
60*d9f75844SAndroid Build Coastguard Worker              k127Utf8CharactersLengthInBytes;  // RFC 8489 section 14.3
61*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_MESSAGE_INTEGRITY:
62*d9f75844SAndroid Build Coastguard Worker       return length ==
63*d9f75844SAndroid Build Coastguard Worker              kMessageIntegrityAttributeLength;  // RFC 8489 section 14.5
64*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_REALM:
65*d9f75844SAndroid Build Coastguard Worker       return length <=
66*d9f75844SAndroid Build Coastguard Worker              k127Utf8CharactersLengthInBytes;  // RFC 8489 section 14.9
67*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_NONCE:
68*d9f75844SAndroid Build Coastguard Worker       return length <=
69*d9f75844SAndroid Build Coastguard Worker              k127Utf8CharactersLengthInBytes;  // RFC 8489 section 14.10
70*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_SOFTWARE:
71*d9f75844SAndroid Build Coastguard Worker       return length <=
72*d9f75844SAndroid Build Coastguard Worker              k127Utf8CharactersLengthInBytes;  // RFC 8489 section 14.14
73*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_DATA:
74*d9f75844SAndroid Build Coastguard Worker       // No length restriction in RFC; it's the content of an UDP datagram,
75*d9f75844SAndroid Build Coastguard Worker       // which in theory can be up to 65.535 bytes.
76*d9f75844SAndroid Build Coastguard Worker       // TODO(bugs.webrtc.org/12179): Write a test to find the real limit.
77*d9f75844SAndroid Build Coastguard Worker       return length <= kTheoreticalMaximumAttributeLength;
78*d9f75844SAndroid Build Coastguard Worker     default:
79*d9f75844SAndroid Build Coastguard Worker       // Return an arbitrary restriction for all other types.
80*d9f75844SAndroid Build Coastguard Worker       return length <= kTheoreticalMaximumAttributeLength;
81*d9f75844SAndroid Build Coastguard Worker   }
82*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_NOTREACHED();
83*d9f75844SAndroid Build Coastguard Worker   return true;
84*d9f75844SAndroid Build Coastguard Worker }
85*d9f75844SAndroid Build Coastguard Worker 
86*d9f75844SAndroid Build Coastguard Worker }  // namespace
87*d9f75844SAndroid Build Coastguard Worker 
88*d9f75844SAndroid Build Coastguard Worker const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[] = "Try Alternate Server";
89*d9f75844SAndroid Build Coastguard Worker const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request";
90*d9f75844SAndroid Build Coastguard Worker const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized";
91*d9f75844SAndroid Build Coastguard Worker const char STUN_ERROR_REASON_UNKNOWN_ATTRIBUTE[] = "Unknown Attribute";
92*d9f75844SAndroid Build Coastguard Worker const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden";
93*d9f75844SAndroid Build Coastguard Worker const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[] = "Allocation Mismatch";
94*d9f75844SAndroid Build Coastguard Worker const char STUN_ERROR_REASON_STALE_NONCE[] = "Stale Nonce";
95*d9f75844SAndroid Build Coastguard Worker const char STUN_ERROR_REASON_WRONG_CREDENTIALS[] = "Wrong Credentials";
96*d9f75844SAndroid Build Coastguard Worker const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[] = "Unsupported Protocol";
97*d9f75844SAndroid Build Coastguard Worker const char STUN_ERROR_REASON_ROLE_CONFLICT[] = "Role Conflict";
98*d9f75844SAndroid Build Coastguard Worker const char STUN_ERROR_REASON_SERVER_ERROR[] = "Server Error";
99*d9f75844SAndroid Build Coastguard Worker 
100*d9f75844SAndroid Build Coastguard Worker const char TURN_MAGIC_COOKIE_VALUE[] = {'\x72', '\xC6', '\x4B', '\xC6'};
101*d9f75844SAndroid Build Coastguard Worker const char EMPTY_TRANSACTION_ID[] = "0000000000000000";
102*d9f75844SAndroid Build Coastguard Worker const uint32_t STUN_FINGERPRINT_XOR_VALUE = 0x5354554E;
103*d9f75844SAndroid Build Coastguard Worker const int SERVER_NOT_REACHABLE_ERROR = 701;
104*d9f75844SAndroid Build Coastguard Worker 
105*d9f75844SAndroid Build Coastguard Worker // StunMessage
106*d9f75844SAndroid Build Coastguard Worker 
StunMessage()107*d9f75844SAndroid Build Coastguard Worker StunMessage::StunMessage()
108*d9f75844SAndroid Build Coastguard Worker     : StunMessage(STUN_INVALID_MESSAGE_TYPE, EMPTY_TRANSACTION_ID) {}
109*d9f75844SAndroid Build Coastguard Worker 
StunMessage(uint16_t type)110*d9f75844SAndroid Build Coastguard Worker StunMessage::StunMessage(uint16_t type)
111*d9f75844SAndroid Build Coastguard Worker     : StunMessage(type, GenerateTransactionId()) {}
112*d9f75844SAndroid Build Coastguard Worker 
StunMessage(uint16_t type,absl::string_view transaction_id)113*d9f75844SAndroid Build Coastguard Worker StunMessage::StunMessage(uint16_t type, absl::string_view transaction_id)
114*d9f75844SAndroid Build Coastguard Worker     : type_(type),
115*d9f75844SAndroid Build Coastguard Worker       transaction_id_(transaction_id),
116*d9f75844SAndroid Build Coastguard Worker       reduced_transaction_id_(ReduceTransactionId(transaction_id_)) {
117*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(IsValidTransactionId(transaction_id_));
118*d9f75844SAndroid Build Coastguard Worker }
119*d9f75844SAndroid Build Coastguard Worker 
120*d9f75844SAndroid Build Coastguard Worker StunMessage::~StunMessage() = default;
121*d9f75844SAndroid Build Coastguard Worker 
IsLegacy() const122*d9f75844SAndroid Build Coastguard Worker bool StunMessage::IsLegacy() const {
123*d9f75844SAndroid Build Coastguard Worker   if (transaction_id_.size() == kStunLegacyTransactionIdLength)
124*d9f75844SAndroid Build Coastguard Worker     return true;
125*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(transaction_id_.size() == kStunTransactionIdLength);
126*d9f75844SAndroid Build Coastguard Worker   return false;
127*d9f75844SAndroid Build Coastguard Worker }
128*d9f75844SAndroid Build Coastguard Worker 
DesignatedExpertRange(int attr_type)129*d9f75844SAndroid Build Coastguard Worker static bool DesignatedExpertRange(int attr_type) {
130*d9f75844SAndroid Build Coastguard Worker   return (attr_type >= 0x4000 && attr_type <= 0x7FFF) ||
131*d9f75844SAndroid Build Coastguard Worker          (attr_type >= 0xC000 && attr_type <= 0xFFFF);
132*d9f75844SAndroid Build Coastguard Worker }
133*d9f75844SAndroid Build Coastguard Worker 
AddAttribute(std::unique_ptr<StunAttribute> attr)134*d9f75844SAndroid Build Coastguard Worker void StunMessage::AddAttribute(std::unique_ptr<StunAttribute> attr) {
135*d9f75844SAndroid Build Coastguard Worker   // Fail any attributes that aren't valid for this type of message,
136*d9f75844SAndroid Build Coastguard Worker   // but allow any type for the range that in the RFC is reserved for
137*d9f75844SAndroid Build Coastguard Worker   // the "designated experts".
138*d9f75844SAndroid Build Coastguard Worker   if (!DesignatedExpertRange(attr->type())) {
139*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_EQ(attr->value_type(), GetAttributeValueType(attr->type()));
140*d9f75844SAndroid Build Coastguard Worker   }
141*d9f75844SAndroid Build Coastguard Worker 
142*d9f75844SAndroid Build Coastguard Worker   attr->SetOwner(this);
143*d9f75844SAndroid Build Coastguard Worker   size_t attr_length = attr->length();
144*d9f75844SAndroid Build Coastguard Worker   if (attr_length % 4 != 0) {
145*d9f75844SAndroid Build Coastguard Worker     attr_length += (4 - (attr_length % 4));
146*d9f75844SAndroid Build Coastguard Worker   }
147*d9f75844SAndroid Build Coastguard Worker   length_ += static_cast<uint16_t>(attr_length + 4);
148*d9f75844SAndroid Build Coastguard Worker 
149*d9f75844SAndroid Build Coastguard Worker   attrs_.push_back(std::move(attr));
150*d9f75844SAndroid Build Coastguard Worker }
151*d9f75844SAndroid Build Coastguard Worker 
RemoveAttribute(int type)152*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<StunAttribute> StunMessage::RemoveAttribute(int type) {
153*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<StunAttribute> attribute;
154*d9f75844SAndroid Build Coastguard Worker   for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
155*d9f75844SAndroid Build Coastguard Worker     if ((*it)->type() == type) {
156*d9f75844SAndroid Build Coastguard Worker       attribute = std::move(*it);
157*d9f75844SAndroid Build Coastguard Worker       attrs_.erase(std::next(it).base());
158*d9f75844SAndroid Build Coastguard Worker       break;
159*d9f75844SAndroid Build Coastguard Worker     }
160*d9f75844SAndroid Build Coastguard Worker   }
161*d9f75844SAndroid Build Coastguard Worker   if (attribute) {
162*d9f75844SAndroid Build Coastguard Worker     attribute->SetOwner(nullptr);
163*d9f75844SAndroid Build Coastguard Worker     size_t attr_length = attribute->length();
164*d9f75844SAndroid Build Coastguard Worker     if (attr_length % 4 != 0) {
165*d9f75844SAndroid Build Coastguard Worker       attr_length += (4 - (attr_length % 4));
166*d9f75844SAndroid Build Coastguard Worker     }
167*d9f75844SAndroid Build Coastguard Worker     length_ -= static_cast<uint16_t>(attr_length + 4);
168*d9f75844SAndroid Build Coastguard Worker   }
169*d9f75844SAndroid Build Coastguard Worker   return attribute;
170*d9f75844SAndroid Build Coastguard Worker }
171*d9f75844SAndroid Build Coastguard Worker 
ClearAttributes()172*d9f75844SAndroid Build Coastguard Worker void StunMessage::ClearAttributes() {
173*d9f75844SAndroid Build Coastguard Worker   for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
174*d9f75844SAndroid Build Coastguard Worker     (*it)->SetOwner(nullptr);
175*d9f75844SAndroid Build Coastguard Worker   }
176*d9f75844SAndroid Build Coastguard Worker   attrs_.clear();
177*d9f75844SAndroid Build Coastguard Worker   length_ = 0;
178*d9f75844SAndroid Build Coastguard Worker }
179*d9f75844SAndroid Build Coastguard Worker 
GetNonComprehendedAttributes() const180*d9f75844SAndroid Build Coastguard Worker std::vector<uint16_t> StunMessage::GetNonComprehendedAttributes() const {
181*d9f75844SAndroid Build Coastguard Worker   std::vector<uint16_t> unknown_attributes;
182*d9f75844SAndroid Build Coastguard Worker   for (auto& attr : attrs_) {
183*d9f75844SAndroid Build Coastguard Worker     // "comprehension-required" range is 0x0000-0x7FFF.
184*d9f75844SAndroid Build Coastguard Worker     if (attr->type() >= 0x0000 && attr->type() <= 0x7FFF &&
185*d9f75844SAndroid Build Coastguard Worker         GetAttributeValueType(attr->type()) == STUN_VALUE_UNKNOWN) {
186*d9f75844SAndroid Build Coastguard Worker       unknown_attributes.push_back(attr->type());
187*d9f75844SAndroid Build Coastguard Worker     }
188*d9f75844SAndroid Build Coastguard Worker   }
189*d9f75844SAndroid Build Coastguard Worker   return unknown_attributes;
190*d9f75844SAndroid Build Coastguard Worker }
191*d9f75844SAndroid Build Coastguard Worker 
GetAddress(int type) const192*d9f75844SAndroid Build Coastguard Worker const StunAddressAttribute* StunMessage::GetAddress(int type) const {
193*d9f75844SAndroid Build Coastguard Worker   switch (type) {
194*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_MAPPED_ADDRESS: {
195*d9f75844SAndroid Build Coastguard Worker       // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
196*d9f75844SAndroid Build Coastguard Worker       // missing.
197*d9f75844SAndroid Build Coastguard Worker       const StunAttribute* mapped_address =
198*d9f75844SAndroid Build Coastguard Worker           GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
199*d9f75844SAndroid Build Coastguard Worker       if (!mapped_address)
200*d9f75844SAndroid Build Coastguard Worker         mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
201*d9f75844SAndroid Build Coastguard Worker       return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
202*d9f75844SAndroid Build Coastguard Worker     }
203*d9f75844SAndroid Build Coastguard Worker 
204*d9f75844SAndroid Build Coastguard Worker     default:
205*d9f75844SAndroid Build Coastguard Worker       return static_cast<const StunAddressAttribute*>(GetAttribute(type));
206*d9f75844SAndroid Build Coastguard Worker   }
207*d9f75844SAndroid Build Coastguard Worker }
208*d9f75844SAndroid Build Coastguard Worker 
GetUInt32(int type) const209*d9f75844SAndroid Build Coastguard Worker const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
210*d9f75844SAndroid Build Coastguard Worker   return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
211*d9f75844SAndroid Build Coastguard Worker }
212*d9f75844SAndroid Build Coastguard Worker 
GetUInt64(int type) const213*d9f75844SAndroid Build Coastguard Worker const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
214*d9f75844SAndroid Build Coastguard Worker   return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
215*d9f75844SAndroid Build Coastguard Worker }
216*d9f75844SAndroid Build Coastguard Worker 
GetByteString(int type) const217*d9f75844SAndroid Build Coastguard Worker const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
218*d9f75844SAndroid Build Coastguard Worker   return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
219*d9f75844SAndroid Build Coastguard Worker }
220*d9f75844SAndroid Build Coastguard Worker 
GetUInt16List(int type) const221*d9f75844SAndroid Build Coastguard Worker const StunUInt16ListAttribute* StunMessage::GetUInt16List(int type) const {
222*d9f75844SAndroid Build Coastguard Worker   return static_cast<const StunUInt16ListAttribute*>(GetAttribute(type));
223*d9f75844SAndroid Build Coastguard Worker }
224*d9f75844SAndroid Build Coastguard Worker 
GetErrorCode() const225*d9f75844SAndroid Build Coastguard Worker const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
226*d9f75844SAndroid Build Coastguard Worker   return static_cast<const StunErrorCodeAttribute*>(
227*d9f75844SAndroid Build Coastguard Worker       GetAttribute(STUN_ATTR_ERROR_CODE));
228*d9f75844SAndroid Build Coastguard Worker }
229*d9f75844SAndroid Build Coastguard Worker 
GetErrorCodeValue() const230*d9f75844SAndroid Build Coastguard Worker int StunMessage::GetErrorCodeValue() const {
231*d9f75844SAndroid Build Coastguard Worker   const StunErrorCodeAttribute* error_attribute = GetErrorCode();
232*d9f75844SAndroid Build Coastguard Worker   return error_attribute ? error_attribute->code() : STUN_ERROR_GLOBAL_FAILURE;
233*d9f75844SAndroid Build Coastguard Worker }
234*d9f75844SAndroid Build Coastguard Worker 
GetUnknownAttributes() const235*d9f75844SAndroid Build Coastguard Worker const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
236*d9f75844SAndroid Build Coastguard Worker   return static_cast<const StunUInt16ListAttribute*>(
237*d9f75844SAndroid Build Coastguard Worker       GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
238*d9f75844SAndroid Build Coastguard Worker }
239*d9f75844SAndroid Build Coastguard Worker 
ValidateMessageIntegrity(const std::string & password)240*d9f75844SAndroid Build Coastguard Worker StunMessage::IntegrityStatus StunMessage::ValidateMessageIntegrity(
241*d9f75844SAndroid Build Coastguard Worker     const std::string& password) {
242*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(integrity_ == IntegrityStatus::kNotSet)
243*d9f75844SAndroid Build Coastguard Worker       << "Usage error: Verification should only be done once";
244*d9f75844SAndroid Build Coastguard Worker   password_ = password;
245*d9f75844SAndroid Build Coastguard Worker   if (GetByteString(STUN_ATTR_MESSAGE_INTEGRITY)) {
246*d9f75844SAndroid Build Coastguard Worker     if (ValidateMessageIntegrityOfType(
247*d9f75844SAndroid Build Coastguard Worker             STUN_ATTR_MESSAGE_INTEGRITY, kStunMessageIntegritySize,
248*d9f75844SAndroid Build Coastguard Worker             buffer_.c_str(), buffer_.size(), password)) {
249*d9f75844SAndroid Build Coastguard Worker       integrity_ = IntegrityStatus::kIntegrityOk;
250*d9f75844SAndroid Build Coastguard Worker     } else {
251*d9f75844SAndroid Build Coastguard Worker       integrity_ = IntegrityStatus::kIntegrityBad;
252*d9f75844SAndroid Build Coastguard Worker     }
253*d9f75844SAndroid Build Coastguard Worker   } else if (GetByteString(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32)) {
254*d9f75844SAndroid Build Coastguard Worker     if (ValidateMessageIntegrityOfType(
255*d9f75844SAndroid Build Coastguard Worker             STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32, kStunMessageIntegrity32Size,
256*d9f75844SAndroid Build Coastguard Worker             buffer_.c_str(), buffer_.size(), password)) {
257*d9f75844SAndroid Build Coastguard Worker       integrity_ = IntegrityStatus::kIntegrityOk;
258*d9f75844SAndroid Build Coastguard Worker     } else {
259*d9f75844SAndroid Build Coastguard Worker       integrity_ = IntegrityStatus::kIntegrityBad;
260*d9f75844SAndroid Build Coastguard Worker     }
261*d9f75844SAndroid Build Coastguard Worker   } else {
262*d9f75844SAndroid Build Coastguard Worker     integrity_ = IntegrityStatus::kNoIntegrity;
263*d9f75844SAndroid Build Coastguard Worker   }
264*d9f75844SAndroid Build Coastguard Worker   // Log the result of integrity checking. See crbug.com/1177125 for background.
265*d9f75844SAndroid Build Coastguard Worker   // Convert args to integer for the benefit of the macros.
266*d9f75844SAndroid Build Coastguard Worker   int bucket_count = static_cast<int>(IntegrityStatus::kMaxValue) + 1;
267*d9f75844SAndroid Build Coastguard Worker   int integrity = static_cast<int>(integrity_);
268*d9f75844SAndroid Build Coastguard Worker   if (IsStunRequestType(type_)) {
269*d9f75844SAndroid Build Coastguard Worker     RTC_HISTOGRAM_ENUMERATION("WebRTC.Stun.Integrity.Request", integrity,
270*d9f75844SAndroid Build Coastguard Worker                               bucket_count);
271*d9f75844SAndroid Build Coastguard Worker   } else if (IsStunSuccessResponseType(type_)) {
272*d9f75844SAndroid Build Coastguard Worker     RTC_HISTOGRAM_ENUMERATION("WebRTC.Stun.Integrity.Response", integrity,
273*d9f75844SAndroid Build Coastguard Worker                               bucket_count);
274*d9f75844SAndroid Build Coastguard Worker   } else if (IsStunIndicationType(type_)) {
275*d9f75844SAndroid Build Coastguard Worker     RTC_HISTOGRAM_ENUMERATION("WebRTC.Stun.Integrity.Indication", integrity,
276*d9f75844SAndroid Build Coastguard Worker                               bucket_count);
277*d9f75844SAndroid Build Coastguard Worker   } else {
278*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(IsStunErrorResponseType(type_));
279*d9f75844SAndroid Build Coastguard Worker     auto* error_attribute = GetErrorCode();
280*d9f75844SAndroid Build Coastguard Worker     if (!error_attribute) {
281*d9f75844SAndroid Build Coastguard Worker       RTC_HISTOGRAM_ENUMERATION(
282*d9f75844SAndroid Build Coastguard Worker           "WebRTC.Stun.Integrity.ErrorResponse.NoErrorAttribute", integrity,
283*d9f75844SAndroid Build Coastguard Worker           bucket_count);
284*d9f75844SAndroid Build Coastguard Worker     } else {
285*d9f75844SAndroid Build Coastguard Worker       switch (error_attribute->code()) {
286*d9f75844SAndroid Build Coastguard Worker         case STUN_ERROR_TRY_ALTERNATE:
287*d9f75844SAndroid Build Coastguard Worker           RTC_HISTOGRAM_ENUMERATION(
288*d9f75844SAndroid Build Coastguard Worker               "WebRTC.Stun.Integrity.ErrorResponse.TryAlternate", integrity,
289*d9f75844SAndroid Build Coastguard Worker               bucket_count);
290*d9f75844SAndroid Build Coastguard Worker           break;
291*d9f75844SAndroid Build Coastguard Worker         case STUN_ERROR_BAD_REQUEST:
292*d9f75844SAndroid Build Coastguard Worker           RTC_HISTOGRAM_ENUMERATION(
293*d9f75844SAndroid Build Coastguard Worker               "WebRTC.Stun.Integrity.ErrorResponse.BadRequest", integrity,
294*d9f75844SAndroid Build Coastguard Worker               bucket_count);
295*d9f75844SAndroid Build Coastguard Worker           break;
296*d9f75844SAndroid Build Coastguard Worker         case STUN_ERROR_UNAUTHORIZED:
297*d9f75844SAndroid Build Coastguard Worker           RTC_HISTOGRAM_ENUMERATION(
298*d9f75844SAndroid Build Coastguard Worker               "WebRTC.Stun.Integrity.ErrorResponse.Unauthorized", integrity,
299*d9f75844SAndroid Build Coastguard Worker               bucket_count);
300*d9f75844SAndroid Build Coastguard Worker           break;
301*d9f75844SAndroid Build Coastguard Worker         case STUN_ERROR_UNKNOWN_ATTRIBUTE:
302*d9f75844SAndroid Build Coastguard Worker           RTC_HISTOGRAM_ENUMERATION(
303*d9f75844SAndroid Build Coastguard Worker               "WebRTC.Stun.Integrity.ErrorResponse.UnknownAttribute", integrity,
304*d9f75844SAndroid Build Coastguard Worker               bucket_count);
305*d9f75844SAndroid Build Coastguard Worker           break;
306*d9f75844SAndroid Build Coastguard Worker         case STUN_ERROR_STALE_NONCE:
307*d9f75844SAndroid Build Coastguard Worker           RTC_HISTOGRAM_ENUMERATION(
308*d9f75844SAndroid Build Coastguard Worker               "WebRTC.Stun.Integrity.ErrorResponse.StaleNonce", integrity,
309*d9f75844SAndroid Build Coastguard Worker               bucket_count);
310*d9f75844SAndroid Build Coastguard Worker           break;
311*d9f75844SAndroid Build Coastguard Worker         case STUN_ERROR_SERVER_ERROR:
312*d9f75844SAndroid Build Coastguard Worker           RTC_HISTOGRAM_ENUMERATION(
313*d9f75844SAndroid Build Coastguard Worker               "WebRTC.Stun.Integrity.ErrorResponse.ServerError", integrity,
314*d9f75844SAndroid Build Coastguard Worker               bucket_count);
315*d9f75844SAndroid Build Coastguard Worker           break;
316*d9f75844SAndroid Build Coastguard Worker         case STUN_ERROR_GLOBAL_FAILURE:
317*d9f75844SAndroid Build Coastguard Worker           RTC_HISTOGRAM_ENUMERATION(
318*d9f75844SAndroid Build Coastguard Worker               "WebRTC.Stun.Integrity.ErrorResponse.GlobalFailure", integrity,
319*d9f75844SAndroid Build Coastguard Worker               bucket_count);
320*d9f75844SAndroid Build Coastguard Worker           break;
321*d9f75844SAndroid Build Coastguard Worker         default:
322*d9f75844SAndroid Build Coastguard Worker           RTC_HISTOGRAM_ENUMERATION(
323*d9f75844SAndroid Build Coastguard Worker               "WebRTC.Stun.Integrity.ErrorResponse.ErrorOther", integrity,
324*d9f75844SAndroid Build Coastguard Worker               bucket_count);
325*d9f75844SAndroid Build Coastguard Worker           break;
326*d9f75844SAndroid Build Coastguard Worker       }
327*d9f75844SAndroid Build Coastguard Worker     }
328*d9f75844SAndroid Build Coastguard Worker   }
329*d9f75844SAndroid Build Coastguard Worker   return integrity_;
330*d9f75844SAndroid Build Coastguard Worker }
331*d9f75844SAndroid Build Coastguard Worker 
RevalidateMessageIntegrity(const std::string & password)332*d9f75844SAndroid Build Coastguard Worker StunMessage::IntegrityStatus StunMessage::RevalidateMessageIntegrity(
333*d9f75844SAndroid Build Coastguard Worker     const std::string& password) {
334*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO) << "Message revalidation, old status was "
335*d9f75844SAndroid Build Coastguard Worker                    << static_cast<int>(integrity_);
336*d9f75844SAndroid Build Coastguard Worker   integrity_ = IntegrityStatus::kNotSet;
337*d9f75844SAndroid Build Coastguard Worker   return ValidateMessageIntegrity(password);
338*d9f75844SAndroid Build Coastguard Worker }
339*d9f75844SAndroid Build Coastguard Worker 
ValidateMessageIntegrityForTesting(const char * data,size_t size,const std::string & password)340*d9f75844SAndroid Build Coastguard Worker bool StunMessage::ValidateMessageIntegrityForTesting(
341*d9f75844SAndroid Build Coastguard Worker     const char* data,
342*d9f75844SAndroid Build Coastguard Worker     size_t size,
343*d9f75844SAndroid Build Coastguard Worker     const std::string& password) {
344*d9f75844SAndroid Build Coastguard Worker   return ValidateMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
345*d9f75844SAndroid Build Coastguard Worker                                         kStunMessageIntegritySize, data, size,
346*d9f75844SAndroid Build Coastguard Worker                                         password);
347*d9f75844SAndroid Build Coastguard Worker }
348*d9f75844SAndroid Build Coastguard Worker 
ValidateMessageIntegrity32ForTesting(const char * data,size_t size,const std::string & password)349*d9f75844SAndroid Build Coastguard Worker bool StunMessage::ValidateMessageIntegrity32ForTesting(
350*d9f75844SAndroid Build Coastguard Worker     const char* data,
351*d9f75844SAndroid Build Coastguard Worker     size_t size,
352*d9f75844SAndroid Build Coastguard Worker     const std::string& password) {
353*d9f75844SAndroid Build Coastguard Worker   return ValidateMessageIntegrityOfType(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32,
354*d9f75844SAndroid Build Coastguard Worker                                         kStunMessageIntegrity32Size, data, size,
355*d9f75844SAndroid Build Coastguard Worker                                         password);
356*d9f75844SAndroid Build Coastguard Worker }
357*d9f75844SAndroid Build Coastguard Worker 
358*d9f75844SAndroid Build Coastguard Worker // Deprecated
ValidateMessageIntegrity(const char * data,size_t size,const std::string & password)359*d9f75844SAndroid Build Coastguard Worker bool StunMessage::ValidateMessageIntegrity(const char* data,
360*d9f75844SAndroid Build Coastguard Worker                                            size_t size,
361*d9f75844SAndroid Build Coastguard Worker                                            const std::string& password) {
362*d9f75844SAndroid Build Coastguard Worker   return ValidateMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
363*d9f75844SAndroid Build Coastguard Worker                                         kStunMessageIntegritySize, data, size,
364*d9f75844SAndroid Build Coastguard Worker                                         password);
365*d9f75844SAndroid Build Coastguard Worker }
366*d9f75844SAndroid Build Coastguard Worker 
367*d9f75844SAndroid Build Coastguard Worker // Deprecated
ValidateMessageIntegrity32(const char * data,size_t size,const std::string & password)368*d9f75844SAndroid Build Coastguard Worker bool StunMessage::ValidateMessageIntegrity32(const char* data,
369*d9f75844SAndroid Build Coastguard Worker                                              size_t size,
370*d9f75844SAndroid Build Coastguard Worker                                              const std::string& password) {
371*d9f75844SAndroid Build Coastguard Worker   return ValidateMessageIntegrityOfType(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32,
372*d9f75844SAndroid Build Coastguard Worker                                         kStunMessageIntegrity32Size, data, size,
373*d9f75844SAndroid Build Coastguard Worker                                         password);
374*d9f75844SAndroid Build Coastguard Worker }
375*d9f75844SAndroid Build Coastguard Worker 
376*d9f75844SAndroid Build Coastguard Worker // Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
377*d9f75844SAndroid Build Coastguard Worker // procedure outlined in RFC 5389, section 15.4.
ValidateMessageIntegrityOfType(int mi_attr_type,size_t mi_attr_size,const char * data,size_t size,const std::string & password)378*d9f75844SAndroid Build Coastguard Worker bool StunMessage::ValidateMessageIntegrityOfType(int mi_attr_type,
379*d9f75844SAndroid Build Coastguard Worker                                                  size_t mi_attr_size,
380*d9f75844SAndroid Build Coastguard Worker                                                  const char* data,
381*d9f75844SAndroid Build Coastguard Worker                                                  size_t size,
382*d9f75844SAndroid Build Coastguard Worker                                                  const std::string& password) {
383*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(mi_attr_size <= kStunMessageIntegritySize);
384*d9f75844SAndroid Build Coastguard Worker 
385*d9f75844SAndroid Build Coastguard Worker   // Verifying the size of the message.
386*d9f75844SAndroid Build Coastguard Worker   if ((size % 4) != 0 || size < kStunHeaderSize) {
387*d9f75844SAndroid Build Coastguard Worker     return false;
388*d9f75844SAndroid Build Coastguard Worker   }
389*d9f75844SAndroid Build Coastguard Worker 
390*d9f75844SAndroid Build Coastguard Worker   // Getting the message length from the STUN header.
391*d9f75844SAndroid Build Coastguard Worker   uint16_t msg_length = rtc::GetBE16(&data[2]);
392*d9f75844SAndroid Build Coastguard Worker   if (size != (msg_length + kStunHeaderSize)) {
393*d9f75844SAndroid Build Coastguard Worker     return false;
394*d9f75844SAndroid Build Coastguard Worker   }
395*d9f75844SAndroid Build Coastguard Worker 
396*d9f75844SAndroid Build Coastguard Worker   // Finding Message Integrity attribute in stun message.
397*d9f75844SAndroid Build Coastguard Worker   size_t current_pos = kStunHeaderSize;
398*d9f75844SAndroid Build Coastguard Worker   bool has_message_integrity_attr = false;
399*d9f75844SAndroid Build Coastguard Worker   while (current_pos + 4 <= size) {
400*d9f75844SAndroid Build Coastguard Worker     uint16_t attr_type, attr_length;
401*d9f75844SAndroid Build Coastguard Worker     // Getting attribute type and length.
402*d9f75844SAndroid Build Coastguard Worker     attr_type = rtc::GetBE16(&data[current_pos]);
403*d9f75844SAndroid Build Coastguard Worker     attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
404*d9f75844SAndroid Build Coastguard Worker 
405*d9f75844SAndroid Build Coastguard Worker     // If M-I, sanity check it, and break out.
406*d9f75844SAndroid Build Coastguard Worker     if (attr_type == mi_attr_type) {
407*d9f75844SAndroid Build Coastguard Worker       if (attr_length != mi_attr_size ||
408*d9f75844SAndroid Build Coastguard Worker           current_pos + sizeof(attr_type) + sizeof(attr_length) + attr_length >
409*d9f75844SAndroid Build Coastguard Worker               size) {
410*d9f75844SAndroid Build Coastguard Worker         return false;
411*d9f75844SAndroid Build Coastguard Worker       }
412*d9f75844SAndroid Build Coastguard Worker       has_message_integrity_attr = true;
413*d9f75844SAndroid Build Coastguard Worker       break;
414*d9f75844SAndroid Build Coastguard Worker     }
415*d9f75844SAndroid Build Coastguard Worker 
416*d9f75844SAndroid Build Coastguard Worker     // Otherwise, skip to the next attribute.
417*d9f75844SAndroid Build Coastguard Worker     current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
418*d9f75844SAndroid Build Coastguard Worker     if ((attr_length % 4) != 0) {
419*d9f75844SAndroid Build Coastguard Worker       current_pos += (4 - (attr_length % 4));
420*d9f75844SAndroid Build Coastguard Worker     }
421*d9f75844SAndroid Build Coastguard Worker   }
422*d9f75844SAndroid Build Coastguard Worker 
423*d9f75844SAndroid Build Coastguard Worker   if (!has_message_integrity_attr) {
424*d9f75844SAndroid Build Coastguard Worker     return false;
425*d9f75844SAndroid Build Coastguard Worker   }
426*d9f75844SAndroid Build Coastguard Worker 
427*d9f75844SAndroid Build Coastguard Worker   // Getting length of the message to calculate Message Integrity.
428*d9f75844SAndroid Build Coastguard Worker   size_t mi_pos = current_pos;
429*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<char[]> temp_data(new char[current_pos]);
430*d9f75844SAndroid Build Coastguard Worker   memcpy(temp_data.get(), data, current_pos);
431*d9f75844SAndroid Build Coastguard Worker   if (size > mi_pos + kStunAttributeHeaderSize + mi_attr_size) {
432*d9f75844SAndroid Build Coastguard Worker     // Stun message has other attributes after message integrity.
433*d9f75844SAndroid Build Coastguard Worker     // Adjust the length parameter in stun message to calculate HMAC.
434*d9f75844SAndroid Build Coastguard Worker     size_t extra_offset =
435*d9f75844SAndroid Build Coastguard Worker         size - (mi_pos + kStunAttributeHeaderSize + mi_attr_size);
436*d9f75844SAndroid Build Coastguard Worker     size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
437*d9f75844SAndroid Build Coastguard Worker 
438*d9f75844SAndroid Build Coastguard Worker     // Writing new length of the STUN message @ Message Length in temp buffer.
439*d9f75844SAndroid Build Coastguard Worker     //      0                   1                   2                   3
440*d9f75844SAndroid Build Coastguard Worker     //      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
441*d9f75844SAndroid Build Coastguard Worker     //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
442*d9f75844SAndroid Build Coastguard Worker     //     |0 0|     STUN Message Type     |         Message Length        |
443*d9f75844SAndroid Build Coastguard Worker     //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
444*d9f75844SAndroid Build Coastguard Worker     rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
445*d9f75844SAndroid Build Coastguard Worker   }
446*d9f75844SAndroid Build Coastguard Worker 
447*d9f75844SAndroid Build Coastguard Worker   char hmac[kStunMessageIntegritySize];
448*d9f75844SAndroid Build Coastguard Worker   size_t ret =
449*d9f75844SAndroid Build Coastguard Worker       rtc::ComputeHmac(rtc::DIGEST_SHA_1, password.c_str(), password.size(),
450*d9f75844SAndroid Build Coastguard Worker                        temp_data.get(), mi_pos, hmac, sizeof(hmac));
451*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(ret == sizeof(hmac));
452*d9f75844SAndroid Build Coastguard Worker   if (ret != sizeof(hmac)) {
453*d9f75844SAndroid Build Coastguard Worker     return false;
454*d9f75844SAndroid Build Coastguard Worker   }
455*d9f75844SAndroid Build Coastguard Worker 
456*d9f75844SAndroid Build Coastguard Worker   // Comparing the calculated HMAC with the one present in the message.
457*d9f75844SAndroid Build Coastguard Worker   return memcmp(data + current_pos + kStunAttributeHeaderSize, hmac,
458*d9f75844SAndroid Build Coastguard Worker                 mi_attr_size) == 0;
459*d9f75844SAndroid Build Coastguard Worker }
460*d9f75844SAndroid Build Coastguard Worker 
AddMessageIntegrity(absl::string_view password)461*d9f75844SAndroid Build Coastguard Worker bool StunMessage::AddMessageIntegrity(absl::string_view password) {
462*d9f75844SAndroid Build Coastguard Worker   return AddMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
463*d9f75844SAndroid Build Coastguard Worker                                    kStunMessageIntegritySize, password);
464*d9f75844SAndroid Build Coastguard Worker }
465*d9f75844SAndroid Build Coastguard Worker 
AddMessageIntegrity32(absl::string_view password)466*d9f75844SAndroid Build Coastguard Worker bool StunMessage::AddMessageIntegrity32(absl::string_view password) {
467*d9f75844SAndroid Build Coastguard Worker   return AddMessageIntegrityOfType(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32,
468*d9f75844SAndroid Build Coastguard Worker                                    kStunMessageIntegrity32Size, password);
469*d9f75844SAndroid Build Coastguard Worker }
470*d9f75844SAndroid Build Coastguard Worker 
AddMessageIntegrityOfType(int attr_type,size_t attr_size,absl::string_view key)471*d9f75844SAndroid Build Coastguard Worker bool StunMessage::AddMessageIntegrityOfType(int attr_type,
472*d9f75844SAndroid Build Coastguard Worker                                             size_t attr_size,
473*d9f75844SAndroid Build Coastguard Worker                                             absl::string_view key) {
474*d9f75844SAndroid Build Coastguard Worker   // Add the attribute with a dummy value. Since this is a known attribute, it
475*d9f75844SAndroid Build Coastguard Worker   // can't fail.
476*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(attr_size <= kStunMessageIntegritySize);
477*d9f75844SAndroid Build Coastguard Worker   auto msg_integrity_attr_ptr = std::make_unique<StunByteStringAttribute>(
478*d9f75844SAndroid Build Coastguard Worker       attr_type, std::string(attr_size, '0'));
479*d9f75844SAndroid Build Coastguard Worker   auto* msg_integrity_attr = msg_integrity_attr_ptr.get();
480*d9f75844SAndroid Build Coastguard Worker   AddAttribute(std::move(msg_integrity_attr_ptr));
481*d9f75844SAndroid Build Coastguard Worker 
482*d9f75844SAndroid Build Coastguard Worker   // Calculate the HMAC for the message.
483*d9f75844SAndroid Build Coastguard Worker   ByteBufferWriter buf;
484*d9f75844SAndroid Build Coastguard Worker   if (!Write(&buf))
485*d9f75844SAndroid Build Coastguard Worker     return false;
486*d9f75844SAndroid Build Coastguard Worker 
487*d9f75844SAndroid Build Coastguard Worker   int msg_len_for_hmac = static_cast<int>(
488*d9f75844SAndroid Build Coastguard Worker       buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
489*d9f75844SAndroid Build Coastguard Worker   char hmac[kStunMessageIntegritySize];
490*d9f75844SAndroid Build Coastguard Worker   size_t ret =
491*d9f75844SAndroid Build Coastguard Worker       rtc::ComputeHmac(rtc::DIGEST_SHA_1, key.data(), key.size(), buf.Data(),
492*d9f75844SAndroid Build Coastguard Worker                        msg_len_for_hmac, hmac, sizeof(hmac));
493*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(ret == sizeof(hmac));
494*d9f75844SAndroid Build Coastguard Worker   if (ret != sizeof(hmac)) {
495*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
496*d9f75844SAndroid Build Coastguard Worker                          "has dummy value.";
497*d9f75844SAndroid Build Coastguard Worker     return false;
498*d9f75844SAndroid Build Coastguard Worker   }
499*d9f75844SAndroid Build Coastguard Worker 
500*d9f75844SAndroid Build Coastguard Worker   // Insert correct HMAC into the attribute.
501*d9f75844SAndroid Build Coastguard Worker   msg_integrity_attr->CopyBytes(hmac, attr_size);
502*d9f75844SAndroid Build Coastguard Worker   password_ = std::string(key);
503*d9f75844SAndroid Build Coastguard Worker   integrity_ = IntegrityStatus::kIntegrityOk;
504*d9f75844SAndroid Build Coastguard Worker   return true;
505*d9f75844SAndroid Build Coastguard Worker }
506*d9f75844SAndroid Build Coastguard Worker 
507*d9f75844SAndroid Build Coastguard Worker // Verifies a message is in fact a STUN message, by performing the checks
508*d9f75844SAndroid Build Coastguard Worker // outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
509*d9f75844SAndroid Build Coastguard Worker // in section 15.5.
ValidateFingerprint(const char * data,size_t size)510*d9f75844SAndroid Build Coastguard Worker bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
511*d9f75844SAndroid Build Coastguard Worker   // Check the message length.
512*d9f75844SAndroid Build Coastguard Worker   size_t fingerprint_attr_size =
513*d9f75844SAndroid Build Coastguard Worker       kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
514*d9f75844SAndroid Build Coastguard Worker   if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
515*d9f75844SAndroid Build Coastguard Worker     return false;
516*d9f75844SAndroid Build Coastguard Worker 
517*d9f75844SAndroid Build Coastguard Worker   // Skip the rest if the magic cookie isn't present.
518*d9f75844SAndroid Build Coastguard Worker   const char* magic_cookie =
519*d9f75844SAndroid Build Coastguard Worker       data + kStunTransactionIdOffset - kStunMagicCookieLength;
520*d9f75844SAndroid Build Coastguard Worker   if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
521*d9f75844SAndroid Build Coastguard Worker     return false;
522*d9f75844SAndroid Build Coastguard Worker 
523*d9f75844SAndroid Build Coastguard Worker   // Check the fingerprint type and length.
524*d9f75844SAndroid Build Coastguard Worker   const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
525*d9f75844SAndroid Build Coastguard Worker   if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
526*d9f75844SAndroid Build Coastguard Worker       rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
527*d9f75844SAndroid Build Coastguard Worker           StunUInt32Attribute::SIZE)
528*d9f75844SAndroid Build Coastguard Worker     return false;
529*d9f75844SAndroid Build Coastguard Worker 
530*d9f75844SAndroid Build Coastguard Worker   // Check the fingerprint value.
531*d9f75844SAndroid Build Coastguard Worker   uint32_t fingerprint =
532*d9f75844SAndroid Build Coastguard Worker       rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
533*d9f75844SAndroid Build Coastguard Worker   return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
534*d9f75844SAndroid Build Coastguard Worker           rtc::ComputeCrc32(data, size - fingerprint_attr_size));
535*d9f75844SAndroid Build Coastguard Worker }
536*d9f75844SAndroid Build Coastguard Worker 
537*d9f75844SAndroid Build Coastguard Worker // static
GenerateTransactionId()538*d9f75844SAndroid Build Coastguard Worker std::string StunMessage::GenerateTransactionId() {
539*d9f75844SAndroid Build Coastguard Worker   return rtc::CreateRandomString(kStunTransactionIdLength);
540*d9f75844SAndroid Build Coastguard Worker }
541*d9f75844SAndroid Build Coastguard Worker 
IsStunMethod(rtc::ArrayView<int> methods,const char * data,size_t size)542*d9f75844SAndroid Build Coastguard Worker bool StunMessage::IsStunMethod(rtc::ArrayView<int> methods,
543*d9f75844SAndroid Build Coastguard Worker                                const char* data,
544*d9f75844SAndroid Build Coastguard Worker                                size_t size) {
545*d9f75844SAndroid Build Coastguard Worker   // Check the message length.
546*d9f75844SAndroid Build Coastguard Worker   if (size % 4 != 0 || size < kStunHeaderSize)
547*d9f75844SAndroid Build Coastguard Worker     return false;
548*d9f75844SAndroid Build Coastguard Worker 
549*d9f75844SAndroid Build Coastguard Worker   // Skip the rest if the magic cookie isn't present.
550*d9f75844SAndroid Build Coastguard Worker   const char* magic_cookie =
551*d9f75844SAndroid Build Coastguard Worker       data + kStunTransactionIdOffset - kStunMagicCookieLength;
552*d9f75844SAndroid Build Coastguard Worker   if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
553*d9f75844SAndroid Build Coastguard Worker     return false;
554*d9f75844SAndroid Build Coastguard Worker 
555*d9f75844SAndroid Build Coastguard Worker   int method = rtc::GetBE16(data);
556*d9f75844SAndroid Build Coastguard Worker   for (int m : methods) {
557*d9f75844SAndroid Build Coastguard Worker     if (m == method) {
558*d9f75844SAndroid Build Coastguard Worker       return true;
559*d9f75844SAndroid Build Coastguard Worker     }
560*d9f75844SAndroid Build Coastguard Worker   }
561*d9f75844SAndroid Build Coastguard Worker   return false;
562*d9f75844SAndroid Build Coastguard Worker }
563*d9f75844SAndroid Build Coastguard Worker 
AddFingerprint()564*d9f75844SAndroid Build Coastguard Worker bool StunMessage::AddFingerprint() {
565*d9f75844SAndroid Build Coastguard Worker   // Add the attribute with a dummy value. Since this is a known attribute,
566*d9f75844SAndroid Build Coastguard Worker   // it can't fail.
567*d9f75844SAndroid Build Coastguard Worker   auto fingerprint_attr_ptr =
568*d9f75844SAndroid Build Coastguard Worker       std::make_unique<StunUInt32Attribute>(STUN_ATTR_FINGERPRINT, 0);
569*d9f75844SAndroid Build Coastguard Worker   auto* fingerprint_attr = fingerprint_attr_ptr.get();
570*d9f75844SAndroid Build Coastguard Worker   AddAttribute(std::move(fingerprint_attr_ptr));
571*d9f75844SAndroid Build Coastguard Worker 
572*d9f75844SAndroid Build Coastguard Worker   // Calculate the CRC-32 for the message and insert it.
573*d9f75844SAndroid Build Coastguard Worker   ByteBufferWriter buf;
574*d9f75844SAndroid Build Coastguard Worker   if (!Write(&buf))
575*d9f75844SAndroid Build Coastguard Worker     return false;
576*d9f75844SAndroid Build Coastguard Worker 
577*d9f75844SAndroid Build Coastguard Worker   int msg_len_for_crc32 = static_cast<int>(
578*d9f75844SAndroid Build Coastguard Worker       buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
579*d9f75844SAndroid Build Coastguard Worker   uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
580*d9f75844SAndroid Build Coastguard Worker 
581*d9f75844SAndroid Build Coastguard Worker   // Insert the correct CRC-32, XORed with a constant, into the attribute.
582*d9f75844SAndroid Build Coastguard Worker   fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
583*d9f75844SAndroid Build Coastguard Worker   return true;
584*d9f75844SAndroid Build Coastguard Worker }
585*d9f75844SAndroid Build Coastguard Worker 
Read(ByteBufferReader * buf)586*d9f75844SAndroid Build Coastguard Worker bool StunMessage::Read(ByteBufferReader* buf) {
587*d9f75844SAndroid Build Coastguard Worker   // Keep a copy of the buffer data around for later verification.
588*d9f75844SAndroid Build Coastguard Worker   buffer_.assign(buf->Data(), buf->Length());
589*d9f75844SAndroid Build Coastguard Worker 
590*d9f75844SAndroid Build Coastguard Worker   if (!buf->ReadUInt16(&type_)) {
591*d9f75844SAndroid Build Coastguard Worker     return false;
592*d9f75844SAndroid Build Coastguard Worker   }
593*d9f75844SAndroid Build Coastguard Worker 
594*d9f75844SAndroid Build Coastguard Worker   if (type_ & 0x8000) {
595*d9f75844SAndroid Build Coastguard Worker     // RTP and RTCP set the MSB of first byte, since first two bits are version,
596*d9f75844SAndroid Build Coastguard Worker     // and version is always 2 (10). If set, this is not a STUN packet.
597*d9f75844SAndroid Build Coastguard Worker     return false;
598*d9f75844SAndroid Build Coastguard Worker   }
599*d9f75844SAndroid Build Coastguard Worker 
600*d9f75844SAndroid Build Coastguard Worker   if (!buf->ReadUInt16(&length_)) {
601*d9f75844SAndroid Build Coastguard Worker     return false;
602*d9f75844SAndroid Build Coastguard Worker   }
603*d9f75844SAndroid Build Coastguard Worker 
604*d9f75844SAndroid Build Coastguard Worker   std::string magic_cookie;
605*d9f75844SAndroid Build Coastguard Worker   if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength)) {
606*d9f75844SAndroid Build Coastguard Worker     return false;
607*d9f75844SAndroid Build Coastguard Worker   }
608*d9f75844SAndroid Build Coastguard Worker 
609*d9f75844SAndroid Build Coastguard Worker   std::string transaction_id;
610*d9f75844SAndroid Build Coastguard Worker   if (!buf->ReadString(&transaction_id, kStunTransactionIdLength)) {
611*d9f75844SAndroid Build Coastguard Worker     return false;
612*d9f75844SAndroid Build Coastguard Worker   }
613*d9f75844SAndroid Build Coastguard Worker 
614*d9f75844SAndroid Build Coastguard Worker   uint32_t magic_cookie_int;
615*d9f75844SAndroid Build Coastguard Worker   static_assert(sizeof(magic_cookie_int) == kStunMagicCookieLength,
616*d9f75844SAndroid Build Coastguard Worker                 "Integer size mismatch: magic_cookie_int and kStunMagicCookie");
617*d9f75844SAndroid Build Coastguard Worker   std::memcpy(&magic_cookie_int, magic_cookie.data(), sizeof(magic_cookie_int));
618*d9f75844SAndroid Build Coastguard Worker   if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
619*d9f75844SAndroid Build Coastguard Worker     // If magic cookie is invalid it means that the peer implements
620*d9f75844SAndroid Build Coastguard Worker     // RFC3489 instead of RFC5389.
621*d9f75844SAndroid Build Coastguard Worker     transaction_id.insert(0, magic_cookie);
622*d9f75844SAndroid Build Coastguard Worker   }
623*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(IsValidTransactionId(transaction_id));
624*d9f75844SAndroid Build Coastguard Worker   transaction_id_ = transaction_id;
625*d9f75844SAndroid Build Coastguard Worker   reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
626*d9f75844SAndroid Build Coastguard Worker 
627*d9f75844SAndroid Build Coastguard Worker   if (length_ != buf->Length()) {
628*d9f75844SAndroid Build Coastguard Worker     return false;
629*d9f75844SAndroid Build Coastguard Worker   }
630*d9f75844SAndroid Build Coastguard Worker 
631*d9f75844SAndroid Build Coastguard Worker   attrs_.resize(0);
632*d9f75844SAndroid Build Coastguard Worker 
633*d9f75844SAndroid Build Coastguard Worker   size_t rest = buf->Length() - length_;
634*d9f75844SAndroid Build Coastguard Worker   while (buf->Length() > rest) {
635*d9f75844SAndroid Build Coastguard Worker     uint16_t attr_type, attr_length;
636*d9f75844SAndroid Build Coastguard Worker     if (!buf->ReadUInt16(&attr_type))
637*d9f75844SAndroid Build Coastguard Worker       return false;
638*d9f75844SAndroid Build Coastguard Worker     if (!buf->ReadUInt16(&attr_length))
639*d9f75844SAndroid Build Coastguard Worker       return false;
640*d9f75844SAndroid Build Coastguard Worker 
641*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<StunAttribute> attr(
642*d9f75844SAndroid Build Coastguard Worker         CreateAttribute(attr_type, attr_length));
643*d9f75844SAndroid Build Coastguard Worker     if (!attr) {
644*d9f75844SAndroid Build Coastguard Worker       // Skip any unknown or malformed attributes.
645*d9f75844SAndroid Build Coastguard Worker       if ((attr_length % 4) != 0) {
646*d9f75844SAndroid Build Coastguard Worker         attr_length += (4 - (attr_length % 4));
647*d9f75844SAndroid Build Coastguard Worker       }
648*d9f75844SAndroid Build Coastguard Worker       if (!buf->Consume(attr_length)) {
649*d9f75844SAndroid Build Coastguard Worker         return false;
650*d9f75844SAndroid Build Coastguard Worker       }
651*d9f75844SAndroid Build Coastguard Worker     } else {
652*d9f75844SAndroid Build Coastguard Worker       if (!attr->Read(buf)) {
653*d9f75844SAndroid Build Coastguard Worker         return false;
654*d9f75844SAndroid Build Coastguard Worker       }
655*d9f75844SAndroid Build Coastguard Worker       attrs_.push_back(std::move(attr));
656*d9f75844SAndroid Build Coastguard Worker     }
657*d9f75844SAndroid Build Coastguard Worker   }
658*d9f75844SAndroid Build Coastguard Worker 
659*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(buf->Length() == rest);
660*d9f75844SAndroid Build Coastguard Worker   return true;
661*d9f75844SAndroid Build Coastguard Worker }
662*d9f75844SAndroid Build Coastguard Worker 
Write(ByteBufferWriter * buf) const663*d9f75844SAndroid Build Coastguard Worker bool StunMessage::Write(ByteBufferWriter* buf) const {
664*d9f75844SAndroid Build Coastguard Worker   buf->WriteUInt16(type_);
665*d9f75844SAndroid Build Coastguard Worker   buf->WriteUInt16(length_);
666*d9f75844SAndroid Build Coastguard Worker   if (!IsLegacy())
667*d9f75844SAndroid Build Coastguard Worker     buf->WriteUInt32(stun_magic_cookie_);
668*d9f75844SAndroid Build Coastguard Worker   buf->WriteString(transaction_id_);
669*d9f75844SAndroid Build Coastguard Worker 
670*d9f75844SAndroid Build Coastguard Worker   for (const auto& attr : attrs_) {
671*d9f75844SAndroid Build Coastguard Worker     buf->WriteUInt16(attr->type());
672*d9f75844SAndroid Build Coastguard Worker     buf->WriteUInt16(static_cast<uint16_t>(attr->length()));
673*d9f75844SAndroid Build Coastguard Worker     if (!attr->Write(buf)) {
674*d9f75844SAndroid Build Coastguard Worker       return false;
675*d9f75844SAndroid Build Coastguard Worker     }
676*d9f75844SAndroid Build Coastguard Worker   }
677*d9f75844SAndroid Build Coastguard Worker 
678*d9f75844SAndroid Build Coastguard Worker   return true;
679*d9f75844SAndroid Build Coastguard Worker }
680*d9f75844SAndroid Build Coastguard Worker 
CreateNew() const681*d9f75844SAndroid Build Coastguard Worker StunMessage* StunMessage::CreateNew() const {
682*d9f75844SAndroid Build Coastguard Worker   return new StunMessage();
683*d9f75844SAndroid Build Coastguard Worker }
684*d9f75844SAndroid Build Coastguard Worker 
SetStunMagicCookie(uint32_t val)685*d9f75844SAndroid Build Coastguard Worker void StunMessage::SetStunMagicCookie(uint32_t val) {
686*d9f75844SAndroid Build Coastguard Worker   stun_magic_cookie_ = val;
687*d9f75844SAndroid Build Coastguard Worker }
688*d9f75844SAndroid Build Coastguard Worker 
SetTransactionIdForTesting(absl::string_view transaction_id)689*d9f75844SAndroid Build Coastguard Worker void StunMessage::SetTransactionIdForTesting(absl::string_view transaction_id) {
690*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(IsValidTransactionId(transaction_id));
691*d9f75844SAndroid Build Coastguard Worker   transaction_id_ = std::string(transaction_id);
692*d9f75844SAndroid Build Coastguard Worker   reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
693*d9f75844SAndroid Build Coastguard Worker }
694*d9f75844SAndroid Build Coastguard Worker 
GetAttributeValueType(int type) const695*d9f75844SAndroid Build Coastguard Worker StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
696*d9f75844SAndroid Build Coastguard Worker   switch (type) {
697*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_MAPPED_ADDRESS:
698*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_ADDRESS;
699*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_USERNAME:
700*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_BYTE_STRING;
701*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_MESSAGE_INTEGRITY:
702*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_BYTE_STRING;
703*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_ERROR_CODE:
704*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_ERROR_CODE;
705*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_UNKNOWN_ATTRIBUTES:
706*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_UINT16_LIST;
707*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_REALM:
708*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_BYTE_STRING;
709*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_NONCE:
710*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_BYTE_STRING;
711*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_XOR_MAPPED_ADDRESS:
712*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_XOR_ADDRESS;
713*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_SOFTWARE:
714*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_BYTE_STRING;
715*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_ALTERNATE_SERVER:
716*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_ADDRESS;
717*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_FINGERPRINT:
718*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_UINT32;
719*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_RETRANSMIT_COUNT:
720*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_UINT32;
721*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_GOOG_LAST_ICE_CHECK_RECEIVED:
722*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_BYTE_STRING;
723*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_GOOG_MISC_INFO:
724*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_UINT16_LIST;
725*d9f75844SAndroid Build Coastguard Worker     default:
726*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_UNKNOWN;
727*d9f75844SAndroid Build Coastguard Worker   }
728*d9f75844SAndroid Build Coastguard Worker }
729*d9f75844SAndroid Build Coastguard Worker 
CreateAttribute(int type,size_t length)730*d9f75844SAndroid Build Coastguard Worker StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
731*d9f75844SAndroid Build Coastguard Worker   StunAttributeValueType value_type = GetAttributeValueType(type);
732*d9f75844SAndroid Build Coastguard Worker   if (value_type != STUN_VALUE_UNKNOWN) {
733*d9f75844SAndroid Build Coastguard Worker     return StunAttribute::Create(value_type, type,
734*d9f75844SAndroid Build Coastguard Worker                                  static_cast<uint16_t>(length), this);
735*d9f75844SAndroid Build Coastguard Worker   } else if (DesignatedExpertRange(type)) {
736*d9f75844SAndroid Build Coastguard Worker     // Read unknown attributes as STUN_VALUE_BYTE_STRING
737*d9f75844SAndroid Build Coastguard Worker     return StunAttribute::Create(STUN_VALUE_BYTE_STRING, type,
738*d9f75844SAndroid Build Coastguard Worker                                  static_cast<uint16_t>(length), this);
739*d9f75844SAndroid Build Coastguard Worker   } else {
740*d9f75844SAndroid Build Coastguard Worker     return NULL;
741*d9f75844SAndroid Build Coastguard Worker   }
742*d9f75844SAndroid Build Coastguard Worker }
743*d9f75844SAndroid Build Coastguard Worker 
GetAttribute(int type) const744*d9f75844SAndroid Build Coastguard Worker const StunAttribute* StunMessage::GetAttribute(int type) const {
745*d9f75844SAndroid Build Coastguard Worker   for (const auto& attr : attrs_) {
746*d9f75844SAndroid Build Coastguard Worker     if (attr->type() == type) {
747*d9f75844SAndroid Build Coastguard Worker       return attr.get();
748*d9f75844SAndroid Build Coastguard Worker     }
749*d9f75844SAndroid Build Coastguard Worker   }
750*d9f75844SAndroid Build Coastguard Worker   return NULL;
751*d9f75844SAndroid Build Coastguard Worker }
752*d9f75844SAndroid Build Coastguard Worker 
IsValidTransactionId(absl::string_view transaction_id)753*d9f75844SAndroid Build Coastguard Worker bool StunMessage::IsValidTransactionId(absl::string_view transaction_id) {
754*d9f75844SAndroid Build Coastguard Worker   return transaction_id.size() == kStunTransactionIdLength ||
755*d9f75844SAndroid Build Coastguard Worker          transaction_id.size() == kStunLegacyTransactionIdLength;
756*d9f75844SAndroid Build Coastguard Worker }
757*d9f75844SAndroid Build Coastguard Worker 
EqualAttributes(const StunMessage * other,std::function<bool (int type)> attribute_type_mask) const758*d9f75844SAndroid Build Coastguard Worker bool StunMessage::EqualAttributes(
759*d9f75844SAndroid Build Coastguard Worker     const StunMessage* other,
760*d9f75844SAndroid Build Coastguard Worker     std::function<bool(int type)> attribute_type_mask) const {
761*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(other != nullptr);
762*d9f75844SAndroid Build Coastguard Worker   rtc::ByteBufferWriter tmp_buffer_ptr1;
763*d9f75844SAndroid Build Coastguard Worker   rtc::ByteBufferWriter tmp_buffer_ptr2;
764*d9f75844SAndroid Build Coastguard Worker   for (const auto& attr : attrs_) {
765*d9f75844SAndroid Build Coastguard Worker     if (attribute_type_mask(attr->type())) {
766*d9f75844SAndroid Build Coastguard Worker       const StunAttribute* other_attr = other->GetAttribute(attr->type());
767*d9f75844SAndroid Build Coastguard Worker       if (other_attr == nullptr) {
768*d9f75844SAndroid Build Coastguard Worker         return false;
769*d9f75844SAndroid Build Coastguard Worker       }
770*d9f75844SAndroid Build Coastguard Worker       tmp_buffer_ptr1.Clear();
771*d9f75844SAndroid Build Coastguard Worker       tmp_buffer_ptr2.Clear();
772*d9f75844SAndroid Build Coastguard Worker       attr->Write(&tmp_buffer_ptr1);
773*d9f75844SAndroid Build Coastguard Worker       other_attr->Write(&tmp_buffer_ptr2);
774*d9f75844SAndroid Build Coastguard Worker       if (tmp_buffer_ptr1.Length() != tmp_buffer_ptr2.Length()) {
775*d9f75844SAndroid Build Coastguard Worker         return false;
776*d9f75844SAndroid Build Coastguard Worker       }
777*d9f75844SAndroid Build Coastguard Worker       if (memcmp(tmp_buffer_ptr1.Data(), tmp_buffer_ptr2.Data(),
778*d9f75844SAndroid Build Coastguard Worker                  tmp_buffer_ptr1.Length()) != 0) {
779*d9f75844SAndroid Build Coastguard Worker         return false;
780*d9f75844SAndroid Build Coastguard Worker       }
781*d9f75844SAndroid Build Coastguard Worker     }
782*d9f75844SAndroid Build Coastguard Worker   }
783*d9f75844SAndroid Build Coastguard Worker 
784*d9f75844SAndroid Build Coastguard Worker   for (const auto& attr : other->attrs_) {
785*d9f75844SAndroid Build Coastguard Worker     if (attribute_type_mask(attr->type())) {
786*d9f75844SAndroid Build Coastguard Worker       const StunAttribute* own_attr = GetAttribute(attr->type());
787*d9f75844SAndroid Build Coastguard Worker       if (own_attr == nullptr) {
788*d9f75844SAndroid Build Coastguard Worker         return false;
789*d9f75844SAndroid Build Coastguard Worker       }
790*d9f75844SAndroid Build Coastguard Worker       // we have already compared all values...
791*d9f75844SAndroid Build Coastguard Worker     }
792*d9f75844SAndroid Build Coastguard Worker   }
793*d9f75844SAndroid Build Coastguard Worker   return true;
794*d9f75844SAndroid Build Coastguard Worker }
795*d9f75844SAndroid Build Coastguard Worker 
796*d9f75844SAndroid Build Coastguard Worker // StunAttribute
797*d9f75844SAndroid Build Coastguard Worker 
StunAttribute(uint16_t type,uint16_t length)798*d9f75844SAndroid Build Coastguard Worker StunAttribute::StunAttribute(uint16_t type, uint16_t length)
799*d9f75844SAndroid Build Coastguard Worker     : type_(type), length_(length) {}
800*d9f75844SAndroid Build Coastguard Worker 
ConsumePadding(ByteBufferReader * buf) const801*d9f75844SAndroid Build Coastguard Worker void StunAttribute::ConsumePadding(ByteBufferReader* buf) const {
802*d9f75844SAndroid Build Coastguard Worker   int remainder = length_ % 4;
803*d9f75844SAndroid Build Coastguard Worker   if (remainder > 0) {
804*d9f75844SAndroid Build Coastguard Worker     buf->Consume(4 - remainder);
805*d9f75844SAndroid Build Coastguard Worker   }
806*d9f75844SAndroid Build Coastguard Worker }
807*d9f75844SAndroid Build Coastguard Worker 
WritePadding(ByteBufferWriter * buf) const808*d9f75844SAndroid Build Coastguard Worker void StunAttribute::WritePadding(ByteBufferWriter* buf) const {
809*d9f75844SAndroid Build Coastguard Worker   int remainder = length_ % 4;
810*d9f75844SAndroid Build Coastguard Worker   if (remainder > 0) {
811*d9f75844SAndroid Build Coastguard Worker     char zeroes[4] = {0};
812*d9f75844SAndroid Build Coastguard Worker     buf->WriteBytes(zeroes, 4 - remainder);
813*d9f75844SAndroid Build Coastguard Worker   }
814*d9f75844SAndroid Build Coastguard Worker }
815*d9f75844SAndroid Build Coastguard Worker 
Create(StunAttributeValueType value_type,uint16_t type,uint16_t length,StunMessage * owner)816*d9f75844SAndroid Build Coastguard Worker StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
817*d9f75844SAndroid Build Coastguard Worker                                      uint16_t type,
818*d9f75844SAndroid Build Coastguard Worker                                      uint16_t length,
819*d9f75844SAndroid Build Coastguard Worker                                      StunMessage* owner) {
820*d9f75844SAndroid Build Coastguard Worker   switch (value_type) {
821*d9f75844SAndroid Build Coastguard Worker     case STUN_VALUE_ADDRESS:
822*d9f75844SAndroid Build Coastguard Worker       return new StunAddressAttribute(type, length);
823*d9f75844SAndroid Build Coastguard Worker     case STUN_VALUE_XOR_ADDRESS:
824*d9f75844SAndroid Build Coastguard Worker       return new StunXorAddressAttribute(type, length, owner);
825*d9f75844SAndroid Build Coastguard Worker     case STUN_VALUE_UINT32:
826*d9f75844SAndroid Build Coastguard Worker       return new StunUInt32Attribute(type);
827*d9f75844SAndroid Build Coastguard Worker     case STUN_VALUE_UINT64:
828*d9f75844SAndroid Build Coastguard Worker       return new StunUInt64Attribute(type);
829*d9f75844SAndroid Build Coastguard Worker     case STUN_VALUE_BYTE_STRING:
830*d9f75844SAndroid Build Coastguard Worker       return new StunByteStringAttribute(type, length);
831*d9f75844SAndroid Build Coastguard Worker     case STUN_VALUE_ERROR_CODE:
832*d9f75844SAndroid Build Coastguard Worker       return new StunErrorCodeAttribute(type, length);
833*d9f75844SAndroid Build Coastguard Worker     case STUN_VALUE_UINT16_LIST:
834*d9f75844SAndroid Build Coastguard Worker       return new StunUInt16ListAttribute(type, length);
835*d9f75844SAndroid Build Coastguard Worker     default:
836*d9f75844SAndroid Build Coastguard Worker       return NULL;
837*d9f75844SAndroid Build Coastguard Worker   }
838*d9f75844SAndroid Build Coastguard Worker }
839*d9f75844SAndroid Build Coastguard Worker 
CreateAddress(uint16_t type)840*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<StunAddressAttribute> StunAttribute::CreateAddress(
841*d9f75844SAndroid Build Coastguard Worker     uint16_t type) {
842*d9f75844SAndroid Build Coastguard Worker   return std::make_unique<StunAddressAttribute>(type, 0);
843*d9f75844SAndroid Build Coastguard Worker }
844*d9f75844SAndroid Build Coastguard Worker 
CreateXorAddress(uint16_t type)845*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<StunXorAddressAttribute> StunAttribute::CreateXorAddress(
846*d9f75844SAndroid Build Coastguard Worker     uint16_t type) {
847*d9f75844SAndroid Build Coastguard Worker   return std::make_unique<StunXorAddressAttribute>(type, 0, nullptr);
848*d9f75844SAndroid Build Coastguard Worker }
849*d9f75844SAndroid Build Coastguard Worker 
CreateUInt64(uint16_t type)850*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<StunUInt64Attribute> StunAttribute::CreateUInt64(
851*d9f75844SAndroid Build Coastguard Worker     uint16_t type) {
852*d9f75844SAndroid Build Coastguard Worker   return std::make_unique<StunUInt64Attribute>(type);
853*d9f75844SAndroid Build Coastguard Worker }
854*d9f75844SAndroid Build Coastguard Worker 
CreateUInt32(uint16_t type)855*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<StunUInt32Attribute> StunAttribute::CreateUInt32(
856*d9f75844SAndroid Build Coastguard Worker     uint16_t type) {
857*d9f75844SAndroid Build Coastguard Worker   return std::make_unique<StunUInt32Attribute>(type);
858*d9f75844SAndroid Build Coastguard Worker }
859*d9f75844SAndroid Build Coastguard Worker 
CreateByteString(uint16_t type)860*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<StunByteStringAttribute> StunAttribute::CreateByteString(
861*d9f75844SAndroid Build Coastguard Worker     uint16_t type) {
862*d9f75844SAndroid Build Coastguard Worker   return std::make_unique<StunByteStringAttribute>(type, 0);
863*d9f75844SAndroid Build Coastguard Worker }
864*d9f75844SAndroid Build Coastguard Worker 
CreateErrorCode()865*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<StunErrorCodeAttribute> StunAttribute::CreateErrorCode() {
866*d9f75844SAndroid Build Coastguard Worker   return std::make_unique<StunErrorCodeAttribute>(
867*d9f75844SAndroid Build Coastguard Worker       STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
868*d9f75844SAndroid Build Coastguard Worker }
869*d9f75844SAndroid Build Coastguard Worker 
870*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<StunUInt16ListAttribute>
CreateUInt16ListAttribute(uint16_t type)871*d9f75844SAndroid Build Coastguard Worker StunAttribute::CreateUInt16ListAttribute(uint16_t type) {
872*d9f75844SAndroid Build Coastguard Worker   return std::make_unique<StunUInt16ListAttribute>(type, 0);
873*d9f75844SAndroid Build Coastguard Worker }
874*d9f75844SAndroid Build Coastguard Worker 
875*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<StunUInt16ListAttribute>
CreateUnknownAttributes()876*d9f75844SAndroid Build Coastguard Worker StunAttribute::CreateUnknownAttributes() {
877*d9f75844SAndroid Build Coastguard Worker   return std::make_unique<StunUInt16ListAttribute>(STUN_ATTR_UNKNOWN_ATTRIBUTES,
878*d9f75844SAndroid Build Coastguard Worker                                                    0);
879*d9f75844SAndroid Build Coastguard Worker }
880*d9f75844SAndroid Build Coastguard Worker 
StunAddressAttribute(uint16_t type,const rtc::SocketAddress & addr)881*d9f75844SAndroid Build Coastguard Worker StunAddressAttribute::StunAddressAttribute(uint16_t type,
882*d9f75844SAndroid Build Coastguard Worker                                            const rtc::SocketAddress& addr)
883*d9f75844SAndroid Build Coastguard Worker     : StunAttribute(type, 0) {
884*d9f75844SAndroid Build Coastguard Worker   SetAddress(addr);
885*d9f75844SAndroid Build Coastguard Worker }
886*d9f75844SAndroid Build Coastguard Worker 
StunAddressAttribute(uint16_t type,uint16_t length)887*d9f75844SAndroid Build Coastguard Worker StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
888*d9f75844SAndroid Build Coastguard Worker     : StunAttribute(type, length) {}
889*d9f75844SAndroid Build Coastguard Worker 
value_type() const890*d9f75844SAndroid Build Coastguard Worker StunAttributeValueType StunAddressAttribute::value_type() const {
891*d9f75844SAndroid Build Coastguard Worker   return STUN_VALUE_ADDRESS;
892*d9f75844SAndroid Build Coastguard Worker }
893*d9f75844SAndroid Build Coastguard Worker 
Read(ByteBufferReader * buf)894*d9f75844SAndroid Build Coastguard Worker bool StunAddressAttribute::Read(ByteBufferReader* buf) {
895*d9f75844SAndroid Build Coastguard Worker   uint8_t dummy;
896*d9f75844SAndroid Build Coastguard Worker   if (!buf->ReadUInt8(&dummy))
897*d9f75844SAndroid Build Coastguard Worker     return false;
898*d9f75844SAndroid Build Coastguard Worker 
899*d9f75844SAndroid Build Coastguard Worker   uint8_t stun_family;
900*d9f75844SAndroid Build Coastguard Worker   if (!buf->ReadUInt8(&stun_family)) {
901*d9f75844SAndroid Build Coastguard Worker     return false;
902*d9f75844SAndroid Build Coastguard Worker   }
903*d9f75844SAndroid Build Coastguard Worker   uint16_t port;
904*d9f75844SAndroid Build Coastguard Worker   if (!buf->ReadUInt16(&port))
905*d9f75844SAndroid Build Coastguard Worker     return false;
906*d9f75844SAndroid Build Coastguard Worker   if (stun_family == STUN_ADDRESS_IPV4) {
907*d9f75844SAndroid Build Coastguard Worker     in_addr v4addr;
908*d9f75844SAndroid Build Coastguard Worker     if (length() != SIZE_IP4) {
909*d9f75844SAndroid Build Coastguard Worker       return false;
910*d9f75844SAndroid Build Coastguard Worker     }
911*d9f75844SAndroid Build Coastguard Worker     if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
912*d9f75844SAndroid Build Coastguard Worker       return false;
913*d9f75844SAndroid Build Coastguard Worker     }
914*d9f75844SAndroid Build Coastguard Worker     rtc::IPAddress ipaddr(v4addr);
915*d9f75844SAndroid Build Coastguard Worker     SetAddress(rtc::SocketAddress(ipaddr, port));
916*d9f75844SAndroid Build Coastguard Worker   } else if (stun_family == STUN_ADDRESS_IPV6) {
917*d9f75844SAndroid Build Coastguard Worker     in6_addr v6addr;
918*d9f75844SAndroid Build Coastguard Worker     if (length() != SIZE_IP6) {
919*d9f75844SAndroid Build Coastguard Worker       return false;
920*d9f75844SAndroid Build Coastguard Worker     }
921*d9f75844SAndroid Build Coastguard Worker     if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
922*d9f75844SAndroid Build Coastguard Worker       return false;
923*d9f75844SAndroid Build Coastguard Worker     }
924*d9f75844SAndroid Build Coastguard Worker     rtc::IPAddress ipaddr(v6addr);
925*d9f75844SAndroid Build Coastguard Worker     SetAddress(rtc::SocketAddress(ipaddr, port));
926*d9f75844SAndroid Build Coastguard Worker   } else {
927*d9f75844SAndroid Build Coastguard Worker     return false;
928*d9f75844SAndroid Build Coastguard Worker   }
929*d9f75844SAndroid Build Coastguard Worker   return true;
930*d9f75844SAndroid Build Coastguard Worker }
931*d9f75844SAndroid Build Coastguard Worker 
Write(ByteBufferWriter * buf) const932*d9f75844SAndroid Build Coastguard Worker bool StunAddressAttribute::Write(ByteBufferWriter* buf) const {
933*d9f75844SAndroid Build Coastguard Worker   StunAddressFamily address_family = family();
934*d9f75844SAndroid Build Coastguard Worker   if (address_family == STUN_ADDRESS_UNDEF) {
935*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
936*d9f75844SAndroid Build Coastguard Worker     return false;
937*d9f75844SAndroid Build Coastguard Worker   }
938*d9f75844SAndroid Build Coastguard Worker   buf->WriteUInt8(0);
939*d9f75844SAndroid Build Coastguard Worker   buf->WriteUInt8(address_family);
940*d9f75844SAndroid Build Coastguard Worker   buf->WriteUInt16(address_.port());
941*d9f75844SAndroid Build Coastguard Worker   switch (address_.family()) {
942*d9f75844SAndroid Build Coastguard Worker     case AF_INET: {
943*d9f75844SAndroid Build Coastguard Worker       in_addr v4addr = address_.ipaddr().ipv4_address();
944*d9f75844SAndroid Build Coastguard Worker       buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
945*d9f75844SAndroid Build Coastguard Worker       break;
946*d9f75844SAndroid Build Coastguard Worker     }
947*d9f75844SAndroid Build Coastguard Worker     case AF_INET6: {
948*d9f75844SAndroid Build Coastguard Worker       in6_addr v6addr = address_.ipaddr().ipv6_address();
949*d9f75844SAndroid Build Coastguard Worker       buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
950*d9f75844SAndroid Build Coastguard Worker       break;
951*d9f75844SAndroid Build Coastguard Worker     }
952*d9f75844SAndroid Build Coastguard Worker   }
953*d9f75844SAndroid Build Coastguard Worker   return true;
954*d9f75844SAndroid Build Coastguard Worker }
955*d9f75844SAndroid Build Coastguard Worker 
StunXorAddressAttribute(uint16_t type,const rtc::SocketAddress & addr)956*d9f75844SAndroid Build Coastguard Worker StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
957*d9f75844SAndroid Build Coastguard Worker                                                  const rtc::SocketAddress& addr)
958*d9f75844SAndroid Build Coastguard Worker     : StunAddressAttribute(type, addr), owner_(NULL) {}
959*d9f75844SAndroid Build Coastguard Worker 
StunXorAddressAttribute(uint16_t type,uint16_t length,StunMessage * owner)960*d9f75844SAndroid Build Coastguard Worker StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
961*d9f75844SAndroid Build Coastguard Worker                                                  uint16_t length,
962*d9f75844SAndroid Build Coastguard Worker                                                  StunMessage* owner)
963*d9f75844SAndroid Build Coastguard Worker     : StunAddressAttribute(type, length), owner_(owner) {}
964*d9f75844SAndroid Build Coastguard Worker 
value_type() const965*d9f75844SAndroid Build Coastguard Worker StunAttributeValueType StunXorAddressAttribute::value_type() const {
966*d9f75844SAndroid Build Coastguard Worker   return STUN_VALUE_XOR_ADDRESS;
967*d9f75844SAndroid Build Coastguard Worker }
968*d9f75844SAndroid Build Coastguard Worker 
SetOwner(StunMessage * owner)969*d9f75844SAndroid Build Coastguard Worker void StunXorAddressAttribute::SetOwner(StunMessage* owner) {
970*d9f75844SAndroid Build Coastguard Worker   owner_ = owner;
971*d9f75844SAndroid Build Coastguard Worker }
972*d9f75844SAndroid Build Coastguard Worker 
GetXoredIP() const973*d9f75844SAndroid Build Coastguard Worker rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
974*d9f75844SAndroid Build Coastguard Worker   if (owner_) {
975*d9f75844SAndroid Build Coastguard Worker     rtc::IPAddress ip = ipaddr();
976*d9f75844SAndroid Build Coastguard Worker     switch (ip.family()) {
977*d9f75844SAndroid Build Coastguard Worker       case AF_INET: {
978*d9f75844SAndroid Build Coastguard Worker         in_addr v4addr = ip.ipv4_address();
979*d9f75844SAndroid Build Coastguard Worker         v4addr.s_addr =
980*d9f75844SAndroid Build Coastguard Worker             (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
981*d9f75844SAndroid Build Coastguard Worker         return rtc::IPAddress(v4addr);
982*d9f75844SAndroid Build Coastguard Worker       }
983*d9f75844SAndroid Build Coastguard Worker       case AF_INET6: {
984*d9f75844SAndroid Build Coastguard Worker         in6_addr v6addr = ip.ipv6_address();
985*d9f75844SAndroid Build Coastguard Worker         const std::string& transaction_id = owner_->transaction_id();
986*d9f75844SAndroid Build Coastguard Worker         if (transaction_id.length() == kStunTransactionIdLength) {
987*d9f75844SAndroid Build Coastguard Worker           uint32_t transactionid_as_ints[3];
988*d9f75844SAndroid Build Coastguard Worker           memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
989*d9f75844SAndroid Build Coastguard Worker                  transaction_id.length());
990*d9f75844SAndroid Build Coastguard Worker           uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
991*d9f75844SAndroid Build Coastguard Worker           // Transaction ID is in network byte order, but magic cookie
992*d9f75844SAndroid Build Coastguard Worker           // is stored in host byte order.
993*d9f75844SAndroid Build Coastguard Worker           ip_as_ints[0] =
994*d9f75844SAndroid Build Coastguard Worker               (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
995*d9f75844SAndroid Build Coastguard Worker           ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
996*d9f75844SAndroid Build Coastguard Worker           ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
997*d9f75844SAndroid Build Coastguard Worker           ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
998*d9f75844SAndroid Build Coastguard Worker           return rtc::IPAddress(v6addr);
999*d9f75844SAndroid Build Coastguard Worker         }
1000*d9f75844SAndroid Build Coastguard Worker         break;
1001*d9f75844SAndroid Build Coastguard Worker       }
1002*d9f75844SAndroid Build Coastguard Worker     }
1003*d9f75844SAndroid Build Coastguard Worker   }
1004*d9f75844SAndroid Build Coastguard Worker   // Invalid ip family or transaction ID, or missing owner.
1005*d9f75844SAndroid Build Coastguard Worker   // Return an AF_UNSPEC address.
1006*d9f75844SAndroid Build Coastguard Worker   return rtc::IPAddress();
1007*d9f75844SAndroid Build Coastguard Worker }
1008*d9f75844SAndroid Build Coastguard Worker 
Read(ByteBufferReader * buf)1009*d9f75844SAndroid Build Coastguard Worker bool StunXorAddressAttribute::Read(ByteBufferReader* buf) {
1010*d9f75844SAndroid Build Coastguard Worker   if (!StunAddressAttribute::Read(buf))
1011*d9f75844SAndroid Build Coastguard Worker     return false;
1012*d9f75844SAndroid Build Coastguard Worker   uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
1013*d9f75844SAndroid Build Coastguard Worker   rtc::IPAddress xored_ip = GetXoredIP();
1014*d9f75844SAndroid Build Coastguard Worker   SetAddress(rtc::SocketAddress(xored_ip, xoredport));
1015*d9f75844SAndroid Build Coastguard Worker   return true;
1016*d9f75844SAndroid Build Coastguard Worker }
1017*d9f75844SAndroid Build Coastguard Worker 
Write(ByteBufferWriter * buf) const1018*d9f75844SAndroid Build Coastguard Worker bool StunXorAddressAttribute::Write(ByteBufferWriter* buf) const {
1019*d9f75844SAndroid Build Coastguard Worker   StunAddressFamily address_family = family();
1020*d9f75844SAndroid Build Coastguard Worker   if (address_family == STUN_ADDRESS_UNDEF) {
1021*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
1022*d9f75844SAndroid Build Coastguard Worker     return false;
1023*d9f75844SAndroid Build Coastguard Worker   }
1024*d9f75844SAndroid Build Coastguard Worker   rtc::IPAddress xored_ip = GetXoredIP();
1025*d9f75844SAndroid Build Coastguard Worker   if (xored_ip.family() == AF_UNSPEC) {
1026*d9f75844SAndroid Build Coastguard Worker     return false;
1027*d9f75844SAndroid Build Coastguard Worker   }
1028*d9f75844SAndroid Build Coastguard Worker   buf->WriteUInt8(0);
1029*d9f75844SAndroid Build Coastguard Worker   buf->WriteUInt8(family());
1030*d9f75844SAndroid Build Coastguard Worker   buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
1031*d9f75844SAndroid Build Coastguard Worker   switch (xored_ip.family()) {
1032*d9f75844SAndroid Build Coastguard Worker     case AF_INET: {
1033*d9f75844SAndroid Build Coastguard Worker       in_addr v4addr = xored_ip.ipv4_address();
1034*d9f75844SAndroid Build Coastguard Worker       buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
1035*d9f75844SAndroid Build Coastguard Worker       break;
1036*d9f75844SAndroid Build Coastguard Worker     }
1037*d9f75844SAndroid Build Coastguard Worker     case AF_INET6: {
1038*d9f75844SAndroid Build Coastguard Worker       in6_addr v6addr = xored_ip.ipv6_address();
1039*d9f75844SAndroid Build Coastguard Worker       buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
1040*d9f75844SAndroid Build Coastguard Worker       break;
1041*d9f75844SAndroid Build Coastguard Worker     }
1042*d9f75844SAndroid Build Coastguard Worker   }
1043*d9f75844SAndroid Build Coastguard Worker   return true;
1044*d9f75844SAndroid Build Coastguard Worker }
1045*d9f75844SAndroid Build Coastguard Worker 
StunUInt32Attribute(uint16_t type,uint32_t value)1046*d9f75844SAndroid Build Coastguard Worker StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
1047*d9f75844SAndroid Build Coastguard Worker     : StunAttribute(type, SIZE), bits_(value) {}
1048*d9f75844SAndroid Build Coastguard Worker 
StunUInt32Attribute(uint16_t type)1049*d9f75844SAndroid Build Coastguard Worker StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
1050*d9f75844SAndroid Build Coastguard Worker     : StunAttribute(type, SIZE), bits_(0) {}
1051*d9f75844SAndroid Build Coastguard Worker 
value_type() const1052*d9f75844SAndroid Build Coastguard Worker StunAttributeValueType StunUInt32Attribute::value_type() const {
1053*d9f75844SAndroid Build Coastguard Worker   return STUN_VALUE_UINT32;
1054*d9f75844SAndroid Build Coastguard Worker }
1055*d9f75844SAndroid Build Coastguard Worker 
GetBit(size_t index) const1056*d9f75844SAndroid Build Coastguard Worker bool StunUInt32Attribute::GetBit(size_t index) const {
1057*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(index < 32);
1058*d9f75844SAndroid Build Coastguard Worker   return static_cast<bool>((bits_ >> index) & 0x1);
1059*d9f75844SAndroid Build Coastguard Worker }
1060*d9f75844SAndroid Build Coastguard Worker 
SetBit(size_t index,bool value)1061*d9f75844SAndroid Build Coastguard Worker void StunUInt32Attribute::SetBit(size_t index, bool value) {
1062*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(index < 32);
1063*d9f75844SAndroid Build Coastguard Worker   bits_ &= ~(1 << index);
1064*d9f75844SAndroid Build Coastguard Worker   bits_ |= value ? (1 << index) : 0;
1065*d9f75844SAndroid Build Coastguard Worker }
1066*d9f75844SAndroid Build Coastguard Worker 
Read(ByteBufferReader * buf)1067*d9f75844SAndroid Build Coastguard Worker bool StunUInt32Attribute::Read(ByteBufferReader* buf) {
1068*d9f75844SAndroid Build Coastguard Worker   if (length() != SIZE || !buf->ReadUInt32(&bits_))
1069*d9f75844SAndroid Build Coastguard Worker     return false;
1070*d9f75844SAndroid Build Coastguard Worker   return true;
1071*d9f75844SAndroid Build Coastguard Worker }
1072*d9f75844SAndroid Build Coastguard Worker 
Write(ByteBufferWriter * buf) const1073*d9f75844SAndroid Build Coastguard Worker bool StunUInt32Attribute::Write(ByteBufferWriter* buf) const {
1074*d9f75844SAndroid Build Coastguard Worker   buf->WriteUInt32(bits_);
1075*d9f75844SAndroid Build Coastguard Worker   return true;
1076*d9f75844SAndroid Build Coastguard Worker }
1077*d9f75844SAndroid Build Coastguard Worker 
StunUInt64Attribute(uint16_t type,uint64_t value)1078*d9f75844SAndroid Build Coastguard Worker StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
1079*d9f75844SAndroid Build Coastguard Worker     : StunAttribute(type, SIZE), bits_(value) {}
1080*d9f75844SAndroid Build Coastguard Worker 
StunUInt64Attribute(uint16_t type)1081*d9f75844SAndroid Build Coastguard Worker StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
1082*d9f75844SAndroid Build Coastguard Worker     : StunAttribute(type, SIZE), bits_(0) {}
1083*d9f75844SAndroid Build Coastguard Worker 
value_type() const1084*d9f75844SAndroid Build Coastguard Worker StunAttributeValueType StunUInt64Attribute::value_type() const {
1085*d9f75844SAndroid Build Coastguard Worker   return STUN_VALUE_UINT64;
1086*d9f75844SAndroid Build Coastguard Worker }
1087*d9f75844SAndroid Build Coastguard Worker 
Read(ByteBufferReader * buf)1088*d9f75844SAndroid Build Coastguard Worker bool StunUInt64Attribute::Read(ByteBufferReader* buf) {
1089*d9f75844SAndroid Build Coastguard Worker   if (length() != SIZE || !buf->ReadUInt64(&bits_))
1090*d9f75844SAndroid Build Coastguard Worker     return false;
1091*d9f75844SAndroid Build Coastguard Worker   return true;
1092*d9f75844SAndroid Build Coastguard Worker }
1093*d9f75844SAndroid Build Coastguard Worker 
Write(ByteBufferWriter * buf) const1094*d9f75844SAndroid Build Coastguard Worker bool StunUInt64Attribute::Write(ByteBufferWriter* buf) const {
1095*d9f75844SAndroid Build Coastguard Worker   buf->WriteUInt64(bits_);
1096*d9f75844SAndroid Build Coastguard Worker   return true;
1097*d9f75844SAndroid Build Coastguard Worker }
1098*d9f75844SAndroid Build Coastguard Worker 
StunByteStringAttribute(uint16_t type)1099*d9f75844SAndroid Build Coastguard Worker StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
1100*d9f75844SAndroid Build Coastguard Worker     : StunAttribute(type, 0), bytes_(NULL) {}
1101*d9f75844SAndroid Build Coastguard Worker 
StunByteStringAttribute(uint16_t type,absl::string_view str)1102*d9f75844SAndroid Build Coastguard Worker StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
1103*d9f75844SAndroid Build Coastguard Worker                                                  absl::string_view str)
1104*d9f75844SAndroid Build Coastguard Worker     : StunAttribute(type, 0), bytes_(NULL) {
1105*d9f75844SAndroid Build Coastguard Worker   CopyBytes(str);
1106*d9f75844SAndroid Build Coastguard Worker }
1107*d9f75844SAndroid Build Coastguard Worker 
StunByteStringAttribute(uint16_t type,const void * bytes,size_t length)1108*d9f75844SAndroid Build Coastguard Worker StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
1109*d9f75844SAndroid Build Coastguard Worker                                                  const void* bytes,
1110*d9f75844SAndroid Build Coastguard Worker                                                  size_t length)
1111*d9f75844SAndroid Build Coastguard Worker     : StunAttribute(type, 0), bytes_(NULL) {
1112*d9f75844SAndroid Build Coastguard Worker   CopyBytes(bytes, length);
1113*d9f75844SAndroid Build Coastguard Worker }
1114*d9f75844SAndroid Build Coastguard Worker 
StunByteStringAttribute(uint16_t type,uint16_t length)1115*d9f75844SAndroid Build Coastguard Worker StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
1116*d9f75844SAndroid Build Coastguard Worker     : StunAttribute(type, length), bytes_(NULL) {}
1117*d9f75844SAndroid Build Coastguard Worker 
~StunByteStringAttribute()1118*d9f75844SAndroid Build Coastguard Worker StunByteStringAttribute::~StunByteStringAttribute() {
1119*d9f75844SAndroid Build Coastguard Worker   delete[] bytes_;
1120*d9f75844SAndroid Build Coastguard Worker }
1121*d9f75844SAndroid Build Coastguard Worker 
value_type() const1122*d9f75844SAndroid Build Coastguard Worker StunAttributeValueType StunByteStringAttribute::value_type() const {
1123*d9f75844SAndroid Build Coastguard Worker   return STUN_VALUE_BYTE_STRING;
1124*d9f75844SAndroid Build Coastguard Worker }
1125*d9f75844SAndroid Build Coastguard Worker 
CopyBytes(absl::string_view bytes)1126*d9f75844SAndroid Build Coastguard Worker void StunByteStringAttribute::CopyBytes(absl::string_view bytes) {
1127*d9f75844SAndroid Build Coastguard Worker   char* new_bytes = new char[bytes.size()];
1128*d9f75844SAndroid Build Coastguard Worker   memcpy(new_bytes, bytes.data(), bytes.size());
1129*d9f75844SAndroid Build Coastguard Worker   SetBytes(new_bytes, bytes.size());
1130*d9f75844SAndroid Build Coastguard Worker }
1131*d9f75844SAndroid Build Coastguard Worker 
CopyBytes(const void * bytes,size_t length)1132*d9f75844SAndroid Build Coastguard Worker void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
1133*d9f75844SAndroid Build Coastguard Worker   char* new_bytes = new char[length];
1134*d9f75844SAndroid Build Coastguard Worker   memcpy(new_bytes, bytes, length);
1135*d9f75844SAndroid Build Coastguard Worker   SetBytes(new_bytes, length);
1136*d9f75844SAndroid Build Coastguard Worker }
1137*d9f75844SAndroid Build Coastguard Worker 
GetByte(size_t index) const1138*d9f75844SAndroid Build Coastguard Worker uint8_t StunByteStringAttribute::GetByte(size_t index) const {
1139*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(bytes_ != NULL);
1140*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(index < length());
1141*d9f75844SAndroid Build Coastguard Worker   return static_cast<uint8_t>(bytes_[index]);
1142*d9f75844SAndroid Build Coastguard Worker }
1143*d9f75844SAndroid Build Coastguard Worker 
SetByte(size_t index,uint8_t value)1144*d9f75844SAndroid Build Coastguard Worker void StunByteStringAttribute::SetByte(size_t index, uint8_t value) {
1145*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(bytes_ != NULL);
1146*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(index < length());
1147*d9f75844SAndroid Build Coastguard Worker   bytes_[index] = value;
1148*d9f75844SAndroid Build Coastguard Worker }
1149*d9f75844SAndroid Build Coastguard Worker 
Read(ByteBufferReader * buf)1150*d9f75844SAndroid Build Coastguard Worker bool StunByteStringAttribute::Read(ByteBufferReader* buf) {
1151*d9f75844SAndroid Build Coastguard Worker   bytes_ = new char[length()];
1152*d9f75844SAndroid Build Coastguard Worker   if (!buf->ReadBytes(bytes_, length())) {
1153*d9f75844SAndroid Build Coastguard Worker     return false;
1154*d9f75844SAndroid Build Coastguard Worker   }
1155*d9f75844SAndroid Build Coastguard Worker 
1156*d9f75844SAndroid Build Coastguard Worker   ConsumePadding(buf);
1157*d9f75844SAndroid Build Coastguard Worker   return true;
1158*d9f75844SAndroid Build Coastguard Worker }
1159*d9f75844SAndroid Build Coastguard Worker 
Write(ByteBufferWriter * buf) const1160*d9f75844SAndroid Build Coastguard Worker bool StunByteStringAttribute::Write(ByteBufferWriter* buf) const {
1161*d9f75844SAndroid Build Coastguard Worker   // Check that length is legal according to specs
1162*d9f75844SAndroid Build Coastguard Worker   if (!LengthValid(type(), length())) {
1163*d9f75844SAndroid Build Coastguard Worker     return false;
1164*d9f75844SAndroid Build Coastguard Worker   }
1165*d9f75844SAndroid Build Coastguard Worker   buf->WriteBytes(bytes_, length());
1166*d9f75844SAndroid Build Coastguard Worker   WritePadding(buf);
1167*d9f75844SAndroid Build Coastguard Worker   return true;
1168*d9f75844SAndroid Build Coastguard Worker }
1169*d9f75844SAndroid Build Coastguard Worker 
SetBytes(char * bytes,size_t length)1170*d9f75844SAndroid Build Coastguard Worker void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
1171*d9f75844SAndroid Build Coastguard Worker   delete[] bytes_;
1172*d9f75844SAndroid Build Coastguard Worker   bytes_ = bytes;
1173*d9f75844SAndroid Build Coastguard Worker   SetLength(static_cast<uint16_t>(length));
1174*d9f75844SAndroid Build Coastguard Worker }
1175*d9f75844SAndroid Build Coastguard Worker 
1176*d9f75844SAndroid Build Coastguard Worker const uint16_t StunErrorCodeAttribute::MIN_SIZE = 4;
1177*d9f75844SAndroid Build Coastguard Worker 
StunErrorCodeAttribute(uint16_t type,int code,const std::string & reason)1178*d9f75844SAndroid Build Coastguard Worker StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type,
1179*d9f75844SAndroid Build Coastguard Worker                                                int code,
1180*d9f75844SAndroid Build Coastguard Worker                                                const std::string& reason)
1181*d9f75844SAndroid Build Coastguard Worker     : StunAttribute(type, 0) {
1182*d9f75844SAndroid Build Coastguard Worker   SetCode(code);
1183*d9f75844SAndroid Build Coastguard Worker   SetReason(reason);
1184*d9f75844SAndroid Build Coastguard Worker }
1185*d9f75844SAndroid Build Coastguard Worker 
StunErrorCodeAttribute(uint16_t type,uint16_t length)1186*d9f75844SAndroid Build Coastguard Worker StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type, uint16_t length)
1187*d9f75844SAndroid Build Coastguard Worker     : StunAttribute(type, length), class_(0), number_(0) {}
1188*d9f75844SAndroid Build Coastguard Worker 
~StunErrorCodeAttribute()1189*d9f75844SAndroid Build Coastguard Worker StunErrorCodeAttribute::~StunErrorCodeAttribute() {}
1190*d9f75844SAndroid Build Coastguard Worker 
value_type() const1191*d9f75844SAndroid Build Coastguard Worker StunAttributeValueType StunErrorCodeAttribute::value_type() const {
1192*d9f75844SAndroid Build Coastguard Worker   return STUN_VALUE_ERROR_CODE;
1193*d9f75844SAndroid Build Coastguard Worker }
1194*d9f75844SAndroid Build Coastguard Worker 
code() const1195*d9f75844SAndroid Build Coastguard Worker int StunErrorCodeAttribute::code() const {
1196*d9f75844SAndroid Build Coastguard Worker   return class_ * 100 + number_;
1197*d9f75844SAndroid Build Coastguard Worker }
1198*d9f75844SAndroid Build Coastguard Worker 
SetCode(int code)1199*d9f75844SAndroid Build Coastguard Worker void StunErrorCodeAttribute::SetCode(int code) {
1200*d9f75844SAndroid Build Coastguard Worker   class_ = static_cast<uint8_t>(code / 100);
1201*d9f75844SAndroid Build Coastguard Worker   number_ = static_cast<uint8_t>(code % 100);
1202*d9f75844SAndroid Build Coastguard Worker }
1203*d9f75844SAndroid Build Coastguard Worker 
SetReason(const std::string & reason)1204*d9f75844SAndroid Build Coastguard Worker void StunErrorCodeAttribute::SetReason(const std::string& reason) {
1205*d9f75844SAndroid Build Coastguard Worker   SetLength(MIN_SIZE + static_cast<uint16_t>(reason.size()));
1206*d9f75844SAndroid Build Coastguard Worker   reason_ = reason;
1207*d9f75844SAndroid Build Coastguard Worker }
1208*d9f75844SAndroid Build Coastguard Worker 
Read(ByteBufferReader * buf)1209*d9f75844SAndroid Build Coastguard Worker bool StunErrorCodeAttribute::Read(ByteBufferReader* buf) {
1210*d9f75844SAndroid Build Coastguard Worker   uint32_t val;
1211*d9f75844SAndroid Build Coastguard Worker   if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
1212*d9f75844SAndroid Build Coastguard Worker     return false;
1213*d9f75844SAndroid Build Coastguard Worker 
1214*d9f75844SAndroid Build Coastguard Worker   if ((val >> 11) != 0)
1215*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "error-code bits not zero";
1216*d9f75844SAndroid Build Coastguard Worker 
1217*d9f75844SAndroid Build Coastguard Worker   class_ = ((val >> 8) & 0x7);
1218*d9f75844SAndroid Build Coastguard Worker   number_ = (val & 0xff);
1219*d9f75844SAndroid Build Coastguard Worker 
1220*d9f75844SAndroid Build Coastguard Worker   if (!buf->ReadString(&reason_, length() - 4))
1221*d9f75844SAndroid Build Coastguard Worker     return false;
1222*d9f75844SAndroid Build Coastguard Worker 
1223*d9f75844SAndroid Build Coastguard Worker   ConsumePadding(buf);
1224*d9f75844SAndroid Build Coastguard Worker   return true;
1225*d9f75844SAndroid Build Coastguard Worker }
1226*d9f75844SAndroid Build Coastguard Worker 
Write(ByteBufferWriter * buf) const1227*d9f75844SAndroid Build Coastguard Worker bool StunErrorCodeAttribute::Write(ByteBufferWriter* buf) const {
1228*d9f75844SAndroid Build Coastguard Worker   buf->WriteUInt32(class_ << 8 | number_);
1229*d9f75844SAndroid Build Coastguard Worker   buf->WriteString(reason_);
1230*d9f75844SAndroid Build Coastguard Worker   WritePadding(buf);
1231*d9f75844SAndroid Build Coastguard Worker   return true;
1232*d9f75844SAndroid Build Coastguard Worker }
1233*d9f75844SAndroid Build Coastguard Worker 
StunUInt16ListAttribute(uint16_t type,uint16_t length)1234*d9f75844SAndroid Build Coastguard Worker StunUInt16ListAttribute::StunUInt16ListAttribute(uint16_t type, uint16_t length)
1235*d9f75844SAndroid Build Coastguard Worker     : StunAttribute(type, length) {
1236*d9f75844SAndroid Build Coastguard Worker   attr_types_ = new std::vector<uint16_t>();
1237*d9f75844SAndroid Build Coastguard Worker }
1238*d9f75844SAndroid Build Coastguard Worker 
~StunUInt16ListAttribute()1239*d9f75844SAndroid Build Coastguard Worker StunUInt16ListAttribute::~StunUInt16ListAttribute() {
1240*d9f75844SAndroid Build Coastguard Worker   delete attr_types_;
1241*d9f75844SAndroid Build Coastguard Worker }
1242*d9f75844SAndroid Build Coastguard Worker 
value_type() const1243*d9f75844SAndroid Build Coastguard Worker StunAttributeValueType StunUInt16ListAttribute::value_type() const {
1244*d9f75844SAndroid Build Coastguard Worker   return STUN_VALUE_UINT16_LIST;
1245*d9f75844SAndroid Build Coastguard Worker }
1246*d9f75844SAndroid Build Coastguard Worker 
Size() const1247*d9f75844SAndroid Build Coastguard Worker size_t StunUInt16ListAttribute::Size() const {
1248*d9f75844SAndroid Build Coastguard Worker   return attr_types_->size();
1249*d9f75844SAndroid Build Coastguard Worker }
1250*d9f75844SAndroid Build Coastguard Worker 
GetType(int index) const1251*d9f75844SAndroid Build Coastguard Worker uint16_t StunUInt16ListAttribute::GetType(int index) const {
1252*d9f75844SAndroid Build Coastguard Worker   return (*attr_types_)[index];
1253*d9f75844SAndroid Build Coastguard Worker }
1254*d9f75844SAndroid Build Coastguard Worker 
SetType(int index,uint16_t value)1255*d9f75844SAndroid Build Coastguard Worker void StunUInt16ListAttribute::SetType(int index, uint16_t value) {
1256*d9f75844SAndroid Build Coastguard Worker   (*attr_types_)[index] = value;
1257*d9f75844SAndroid Build Coastguard Worker }
1258*d9f75844SAndroid Build Coastguard Worker 
AddType(uint16_t value)1259*d9f75844SAndroid Build Coastguard Worker void StunUInt16ListAttribute::AddType(uint16_t value) {
1260*d9f75844SAndroid Build Coastguard Worker   attr_types_->push_back(value);
1261*d9f75844SAndroid Build Coastguard Worker   SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
1262*d9f75844SAndroid Build Coastguard Worker }
1263*d9f75844SAndroid Build Coastguard Worker 
AddTypeAtIndex(uint16_t index,uint16_t value)1264*d9f75844SAndroid Build Coastguard Worker void StunUInt16ListAttribute::AddTypeAtIndex(uint16_t index, uint16_t value) {
1265*d9f75844SAndroid Build Coastguard Worker   if (attr_types_->size() < static_cast<size_t>(index + 1)) {
1266*d9f75844SAndroid Build Coastguard Worker     attr_types_->resize(index + 1);
1267*d9f75844SAndroid Build Coastguard Worker   }
1268*d9f75844SAndroid Build Coastguard Worker   (*attr_types_)[index] = value;
1269*d9f75844SAndroid Build Coastguard Worker   SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
1270*d9f75844SAndroid Build Coastguard Worker }
1271*d9f75844SAndroid Build Coastguard Worker 
Read(ByteBufferReader * buf)1272*d9f75844SAndroid Build Coastguard Worker bool StunUInt16ListAttribute::Read(ByteBufferReader* buf) {
1273*d9f75844SAndroid Build Coastguard Worker   if (length() % 2) {
1274*d9f75844SAndroid Build Coastguard Worker     return false;
1275*d9f75844SAndroid Build Coastguard Worker   }
1276*d9f75844SAndroid Build Coastguard Worker 
1277*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < length() / 2; i++) {
1278*d9f75844SAndroid Build Coastguard Worker     uint16_t attr;
1279*d9f75844SAndroid Build Coastguard Worker     if (!buf->ReadUInt16(&attr))
1280*d9f75844SAndroid Build Coastguard Worker       return false;
1281*d9f75844SAndroid Build Coastguard Worker     attr_types_->push_back(attr);
1282*d9f75844SAndroid Build Coastguard Worker   }
1283*d9f75844SAndroid Build Coastguard Worker   // Padding of these attributes is done in RFC 5389 style. This is
1284*d9f75844SAndroid Build Coastguard Worker   // slightly different from RFC3489, but it shouldn't be important.
1285*d9f75844SAndroid Build Coastguard Worker   // RFC3489 pads out to a 32 bit boundary by duplicating one of the
1286*d9f75844SAndroid Build Coastguard Worker   // entries in the list (not necessarily the last one - it's unspecified).
1287*d9f75844SAndroid Build Coastguard Worker   // RFC5389 pads on the end, and the bytes are always ignored.
1288*d9f75844SAndroid Build Coastguard Worker   ConsumePadding(buf);
1289*d9f75844SAndroid Build Coastguard Worker   return true;
1290*d9f75844SAndroid Build Coastguard Worker }
1291*d9f75844SAndroid Build Coastguard Worker 
Write(ByteBufferWriter * buf) const1292*d9f75844SAndroid Build Coastguard Worker bool StunUInt16ListAttribute::Write(ByteBufferWriter* buf) const {
1293*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < attr_types_->size(); ++i) {
1294*d9f75844SAndroid Build Coastguard Worker     buf->WriteUInt16((*attr_types_)[i]);
1295*d9f75844SAndroid Build Coastguard Worker   }
1296*d9f75844SAndroid Build Coastguard Worker   WritePadding(buf);
1297*d9f75844SAndroid Build Coastguard Worker   return true;
1298*d9f75844SAndroid Build Coastguard Worker }
1299*d9f75844SAndroid Build Coastguard Worker 
StunMethodToString(int msg_type)1300*d9f75844SAndroid Build Coastguard Worker std::string StunMethodToString(int msg_type) {
1301*d9f75844SAndroid Build Coastguard Worker   switch (msg_type) {
1302*d9f75844SAndroid Build Coastguard Worker     case STUN_BINDING_REQUEST:
1303*d9f75844SAndroid Build Coastguard Worker       return "STUN BINDING request";
1304*d9f75844SAndroid Build Coastguard Worker     case STUN_BINDING_INDICATION:
1305*d9f75844SAndroid Build Coastguard Worker       return "STUN BINDING indication";
1306*d9f75844SAndroid Build Coastguard Worker     case STUN_BINDING_RESPONSE:
1307*d9f75844SAndroid Build Coastguard Worker       return "STUN BINDING response";
1308*d9f75844SAndroid Build Coastguard Worker     case STUN_BINDING_ERROR_RESPONSE:
1309*d9f75844SAndroid Build Coastguard Worker       return "STUN BINDING error response";
1310*d9f75844SAndroid Build Coastguard Worker     case GOOG_PING_REQUEST:
1311*d9f75844SAndroid Build Coastguard Worker       return "GOOG PING request";
1312*d9f75844SAndroid Build Coastguard Worker     case GOOG_PING_RESPONSE:
1313*d9f75844SAndroid Build Coastguard Worker       return "GOOG PING response";
1314*d9f75844SAndroid Build Coastguard Worker     case GOOG_PING_ERROR_RESPONSE:
1315*d9f75844SAndroid Build Coastguard Worker       return "GOOG PING error response";
1316*d9f75844SAndroid Build Coastguard Worker     case STUN_ALLOCATE_REQUEST:
1317*d9f75844SAndroid Build Coastguard Worker       return "TURN ALLOCATE request";
1318*d9f75844SAndroid Build Coastguard Worker     case STUN_ALLOCATE_RESPONSE:
1319*d9f75844SAndroid Build Coastguard Worker       return "TURN ALLOCATE response";
1320*d9f75844SAndroid Build Coastguard Worker     case STUN_ALLOCATE_ERROR_RESPONSE:
1321*d9f75844SAndroid Build Coastguard Worker       return "TURN ALLOCATE error response";
1322*d9f75844SAndroid Build Coastguard Worker     case TURN_REFRESH_REQUEST:
1323*d9f75844SAndroid Build Coastguard Worker       return "TURN REFRESH request";
1324*d9f75844SAndroid Build Coastguard Worker     case TURN_REFRESH_RESPONSE:
1325*d9f75844SAndroid Build Coastguard Worker       return "TURN REFRESH response";
1326*d9f75844SAndroid Build Coastguard Worker     case TURN_REFRESH_ERROR_RESPONSE:
1327*d9f75844SAndroid Build Coastguard Worker       return "TURN REFRESH error response";
1328*d9f75844SAndroid Build Coastguard Worker     case TURN_SEND_INDICATION:
1329*d9f75844SAndroid Build Coastguard Worker       return "TURN SEND INDICATION";
1330*d9f75844SAndroid Build Coastguard Worker     case TURN_DATA_INDICATION:
1331*d9f75844SAndroid Build Coastguard Worker       return "TURN DATA INDICATION";
1332*d9f75844SAndroid Build Coastguard Worker     case TURN_CREATE_PERMISSION_REQUEST:
1333*d9f75844SAndroid Build Coastguard Worker       return "TURN CREATE PERMISSION request";
1334*d9f75844SAndroid Build Coastguard Worker     case TURN_CREATE_PERMISSION_RESPONSE:
1335*d9f75844SAndroid Build Coastguard Worker       return "TURN CREATE PERMISSION response";
1336*d9f75844SAndroid Build Coastguard Worker     case TURN_CREATE_PERMISSION_ERROR_RESPONSE:
1337*d9f75844SAndroid Build Coastguard Worker       return "TURN CREATE PERMISSION error response";
1338*d9f75844SAndroid Build Coastguard Worker     case TURN_CHANNEL_BIND_REQUEST:
1339*d9f75844SAndroid Build Coastguard Worker       return "TURN CHANNEL BIND request";
1340*d9f75844SAndroid Build Coastguard Worker     case TURN_CHANNEL_BIND_RESPONSE:
1341*d9f75844SAndroid Build Coastguard Worker       return "TURN CHANNEL BIND response";
1342*d9f75844SAndroid Build Coastguard Worker     case TURN_CHANNEL_BIND_ERROR_RESPONSE:
1343*d9f75844SAndroid Build Coastguard Worker       return "TURN CHANNEL BIND error response";
1344*d9f75844SAndroid Build Coastguard Worker     default:
1345*d9f75844SAndroid Build Coastguard Worker       return "UNKNOWN<" + std::to_string(msg_type) + ">";
1346*d9f75844SAndroid Build Coastguard Worker   }
1347*d9f75844SAndroid Build Coastguard Worker }
1348*d9f75844SAndroid Build Coastguard Worker 
GetStunSuccessResponseType(int req_type)1349*d9f75844SAndroid Build Coastguard Worker int GetStunSuccessResponseType(int req_type) {
1350*d9f75844SAndroid Build Coastguard Worker   return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
1351*d9f75844SAndroid Build Coastguard Worker }
1352*d9f75844SAndroid Build Coastguard Worker 
GetStunErrorResponseType(int req_type)1353*d9f75844SAndroid Build Coastguard Worker int GetStunErrorResponseType(int req_type) {
1354*d9f75844SAndroid Build Coastguard Worker   return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
1355*d9f75844SAndroid Build Coastguard Worker }
1356*d9f75844SAndroid Build Coastguard Worker 
IsStunRequestType(int msg_type)1357*d9f75844SAndroid Build Coastguard Worker bool IsStunRequestType(int msg_type) {
1358*d9f75844SAndroid Build Coastguard Worker   return ((msg_type & kStunTypeMask) == 0x000);
1359*d9f75844SAndroid Build Coastguard Worker }
1360*d9f75844SAndroid Build Coastguard Worker 
IsStunIndicationType(int msg_type)1361*d9f75844SAndroid Build Coastguard Worker bool IsStunIndicationType(int msg_type) {
1362*d9f75844SAndroid Build Coastguard Worker   return ((msg_type & kStunTypeMask) == 0x010);
1363*d9f75844SAndroid Build Coastguard Worker }
1364*d9f75844SAndroid Build Coastguard Worker 
IsStunSuccessResponseType(int msg_type)1365*d9f75844SAndroid Build Coastguard Worker bool IsStunSuccessResponseType(int msg_type) {
1366*d9f75844SAndroid Build Coastguard Worker   return ((msg_type & kStunTypeMask) == 0x100);
1367*d9f75844SAndroid Build Coastguard Worker }
1368*d9f75844SAndroid Build Coastguard Worker 
IsStunErrorResponseType(int msg_type)1369*d9f75844SAndroid Build Coastguard Worker bool IsStunErrorResponseType(int msg_type) {
1370*d9f75844SAndroid Build Coastguard Worker   return ((msg_type & kStunTypeMask) == 0x110);
1371*d9f75844SAndroid Build Coastguard Worker }
1372*d9f75844SAndroid Build Coastguard Worker 
ComputeStunCredentialHash(const std::string & username,const std::string & realm,const std::string & password,std::string * hash)1373*d9f75844SAndroid Build Coastguard Worker bool ComputeStunCredentialHash(const std::string& username,
1374*d9f75844SAndroid Build Coastguard Worker                                const std::string& realm,
1375*d9f75844SAndroid Build Coastguard Worker                                const std::string& password,
1376*d9f75844SAndroid Build Coastguard Worker                                std::string* hash) {
1377*d9f75844SAndroid Build Coastguard Worker   // http://tools.ietf.org/html/rfc5389#section-15.4
1378*d9f75844SAndroid Build Coastguard Worker   // long-term credentials will be calculated using the key and key is
1379*d9f75844SAndroid Build Coastguard Worker   // key = MD5(username ":" realm ":" SASLprep(password))
1380*d9f75844SAndroid Build Coastguard Worker   std::string input = username;
1381*d9f75844SAndroid Build Coastguard Worker   input += ':';
1382*d9f75844SAndroid Build Coastguard Worker   input += realm;
1383*d9f75844SAndroid Build Coastguard Worker   input += ':';
1384*d9f75844SAndroid Build Coastguard Worker   input += password;
1385*d9f75844SAndroid Build Coastguard Worker 
1386*d9f75844SAndroid Build Coastguard Worker   char digest[rtc::MessageDigest::kMaxSize];
1387*d9f75844SAndroid Build Coastguard Worker   size_t size = rtc::ComputeDigest(rtc::DIGEST_MD5, input.c_str(), input.size(),
1388*d9f75844SAndroid Build Coastguard Worker                                    digest, sizeof(digest));
1389*d9f75844SAndroid Build Coastguard Worker   if (size == 0) {
1390*d9f75844SAndroid Build Coastguard Worker     return false;
1391*d9f75844SAndroid Build Coastguard Worker   }
1392*d9f75844SAndroid Build Coastguard Worker 
1393*d9f75844SAndroid Build Coastguard Worker   *hash = std::string(digest, size);
1394*d9f75844SAndroid Build Coastguard Worker   return true;
1395*d9f75844SAndroid Build Coastguard Worker }
1396*d9f75844SAndroid Build Coastguard Worker 
CopyStunAttribute(const StunAttribute & attribute,rtc::ByteBufferWriter * tmp_buffer_ptr)1397*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<StunAttribute> CopyStunAttribute(
1398*d9f75844SAndroid Build Coastguard Worker     const StunAttribute& attribute,
1399*d9f75844SAndroid Build Coastguard Worker     rtc::ByteBufferWriter* tmp_buffer_ptr) {
1400*d9f75844SAndroid Build Coastguard Worker   ByteBufferWriter tmpBuffer;
1401*d9f75844SAndroid Build Coastguard Worker   if (tmp_buffer_ptr == nullptr) {
1402*d9f75844SAndroid Build Coastguard Worker     tmp_buffer_ptr = &tmpBuffer;
1403*d9f75844SAndroid Build Coastguard Worker   }
1404*d9f75844SAndroid Build Coastguard Worker 
1405*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<StunAttribute> copy(StunAttribute::Create(
1406*d9f75844SAndroid Build Coastguard Worker       attribute.value_type(), attribute.type(),
1407*d9f75844SAndroid Build Coastguard Worker       static_cast<uint16_t>(attribute.length()), nullptr));
1408*d9f75844SAndroid Build Coastguard Worker 
1409*d9f75844SAndroid Build Coastguard Worker   if (!copy) {
1410*d9f75844SAndroid Build Coastguard Worker     return nullptr;
1411*d9f75844SAndroid Build Coastguard Worker   }
1412*d9f75844SAndroid Build Coastguard Worker   tmp_buffer_ptr->Clear();
1413*d9f75844SAndroid Build Coastguard Worker   if (!attribute.Write(tmp_buffer_ptr)) {
1414*d9f75844SAndroid Build Coastguard Worker     return nullptr;
1415*d9f75844SAndroid Build Coastguard Worker   }
1416*d9f75844SAndroid Build Coastguard Worker   rtc::ByteBufferReader reader(*tmp_buffer_ptr);
1417*d9f75844SAndroid Build Coastguard Worker   if (!copy->Read(&reader)) {
1418*d9f75844SAndroid Build Coastguard Worker     return nullptr;
1419*d9f75844SAndroid Build Coastguard Worker   }
1420*d9f75844SAndroid Build Coastguard Worker 
1421*d9f75844SAndroid Build Coastguard Worker   return copy;
1422*d9f75844SAndroid Build Coastguard Worker }
1423*d9f75844SAndroid Build Coastguard Worker 
GetAttributeValueType(int type) const1424*d9f75844SAndroid Build Coastguard Worker StunAttributeValueType RelayMessage::GetAttributeValueType(int type) const {
1425*d9f75844SAndroid Build Coastguard Worker   switch (type) {
1426*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_LIFETIME:
1427*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_UINT32;
1428*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_MAGIC_COOKIE:
1429*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_BYTE_STRING;
1430*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_BANDWIDTH:
1431*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_UINT32;
1432*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_DESTINATION_ADDRESS:
1433*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_ADDRESS;
1434*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_SOURCE_ADDRESS2:
1435*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_ADDRESS;
1436*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_DATA:
1437*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_BYTE_STRING;
1438*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_OPTIONS:
1439*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_UINT32;
1440*d9f75844SAndroid Build Coastguard Worker     default:
1441*d9f75844SAndroid Build Coastguard Worker       return StunMessage::GetAttributeValueType(type);
1442*d9f75844SAndroid Build Coastguard Worker   }
1443*d9f75844SAndroid Build Coastguard Worker }
1444*d9f75844SAndroid Build Coastguard Worker 
CreateNew() const1445*d9f75844SAndroid Build Coastguard Worker StunMessage* RelayMessage::CreateNew() const {
1446*d9f75844SAndroid Build Coastguard Worker   return new RelayMessage();
1447*d9f75844SAndroid Build Coastguard Worker }
1448*d9f75844SAndroid Build Coastguard Worker 
GetAttributeValueType(int type) const1449*d9f75844SAndroid Build Coastguard Worker StunAttributeValueType TurnMessage::GetAttributeValueType(int type) const {
1450*d9f75844SAndroid Build Coastguard Worker   switch (type) {
1451*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_CHANNEL_NUMBER:
1452*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_UINT32;
1453*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_TURN_LIFETIME:
1454*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_UINT32;
1455*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_XOR_PEER_ADDRESS:
1456*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_XOR_ADDRESS;
1457*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_DATA:
1458*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_BYTE_STRING;
1459*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_XOR_RELAYED_ADDRESS:
1460*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_XOR_ADDRESS;
1461*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_EVEN_PORT:
1462*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_BYTE_STRING;
1463*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_REQUESTED_TRANSPORT:
1464*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_UINT32;
1465*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_DONT_FRAGMENT:
1466*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_BYTE_STRING;
1467*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_RESERVATION_TOKEN:
1468*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_BYTE_STRING;
1469*d9f75844SAndroid Build Coastguard Worker     default:
1470*d9f75844SAndroid Build Coastguard Worker       return StunMessage::GetAttributeValueType(type);
1471*d9f75844SAndroid Build Coastguard Worker   }
1472*d9f75844SAndroid Build Coastguard Worker }
1473*d9f75844SAndroid Build Coastguard Worker 
CreateNew() const1474*d9f75844SAndroid Build Coastguard Worker StunMessage* TurnMessage::CreateNew() const {
1475*d9f75844SAndroid Build Coastguard Worker   return new TurnMessage();
1476*d9f75844SAndroid Build Coastguard Worker }
1477*d9f75844SAndroid Build Coastguard Worker 
GetAttributeValueType(int type) const1478*d9f75844SAndroid Build Coastguard Worker StunAttributeValueType IceMessage::GetAttributeValueType(int type) const {
1479*d9f75844SAndroid Build Coastguard Worker   switch (type) {
1480*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_PRIORITY:
1481*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_GOOG_NETWORK_INFO:
1482*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_NOMINATION:
1483*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_UINT32;
1484*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_USE_CANDIDATE:
1485*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_BYTE_STRING;
1486*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_ICE_CONTROLLED:
1487*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_UINT64;
1488*d9f75844SAndroid Build Coastguard Worker     case STUN_ATTR_ICE_CONTROLLING:
1489*d9f75844SAndroid Build Coastguard Worker       return STUN_VALUE_UINT64;
1490*d9f75844SAndroid Build Coastguard Worker     default:
1491*d9f75844SAndroid Build Coastguard Worker       return StunMessage::GetAttributeValueType(type);
1492*d9f75844SAndroid Build Coastguard Worker   }
1493*d9f75844SAndroid Build Coastguard Worker }
1494*d9f75844SAndroid Build Coastguard Worker 
CreateNew() const1495*d9f75844SAndroid Build Coastguard Worker StunMessage* IceMessage::CreateNew() const {
1496*d9f75844SAndroid Build Coastguard Worker   return new IceMessage();
1497*d9f75844SAndroid Build Coastguard Worker }
1498*d9f75844SAndroid Build Coastguard Worker 
Clone() const1499*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<StunMessage> StunMessage::Clone() const {
1500*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<StunMessage> copy(CreateNew());
1501*d9f75844SAndroid Build Coastguard Worker   if (!copy) {
1502*d9f75844SAndroid Build Coastguard Worker     return nullptr;
1503*d9f75844SAndroid Build Coastguard Worker   }
1504*d9f75844SAndroid Build Coastguard Worker   rtc::ByteBufferWriter buf;
1505*d9f75844SAndroid Build Coastguard Worker   if (!Write(&buf)) {
1506*d9f75844SAndroid Build Coastguard Worker     return nullptr;
1507*d9f75844SAndroid Build Coastguard Worker   }
1508*d9f75844SAndroid Build Coastguard Worker   rtc::ByteBufferReader reader(buf);
1509*d9f75844SAndroid Build Coastguard Worker   if (!copy->Read(&reader)) {
1510*d9f75844SAndroid Build Coastguard Worker     return nullptr;
1511*d9f75844SAndroid Build Coastguard Worker   }
1512*d9f75844SAndroid Build Coastguard Worker   return copy;
1513*d9f75844SAndroid Build Coastguard Worker }
1514*d9f75844SAndroid Build Coastguard Worker 
1515*d9f75844SAndroid Build Coastguard Worker }  // namespace cricket
1516