// TODO(mallinath): Move these to a common place. bool IsTurnChannelData(uint16_t msg_type) { // The first two bits of a channel data message are 0b01. return ((msg_type & 0xC000) == 0x4000);
}
void TurnServer::OnNewInternalConnection(Socket* socket) {
RTC_DCHECK_RUN_ON(thread_); auto iter = server_listen_sockets_.find(socket);
RTC_DCHECK(iter != server_listen_sockets_.end());
// Check if someone is trying to connect to us.
SocketAddress accept_addr;
std::unique_ptr<Socket> accepted_socket =
absl::WrapUnique(socket->Accept(&accept_addr)); if (accepted_socket != nullptr) { const ServerSocketInfo& info = iter->second; if (info.ssl_adapter_factory) {
std::unique_ptr<SSLAdapter> ssl_adapter = absl::WrapUnique(
info.ssl_adapter_factory->CreateAdapter(accepted_socket.release()));
ssl_adapter->StartSSL("");
accepted_socket = std::move(ssl_adapter);
} auto tcp_socket =
std::make_unique<AsyncStunTCPSocket>(env_, std::move(accepted_socket));
tcp_socket->SubscribeCloseEvent(this,
[this](AsyncPacketSocket* s, int err) {
OnInternalSocketClose(s, err);
}); // Finally add the socket so it can start communicating with the client.
AddInternalSocket(std::move(tcp_socket), info.proto);
}
}
void TurnServer::OnInternalSocketClose(AsyncPacketSocket* socket, int err) {
RTC_DCHECK_RUN_ON(thread_); if (auto iter = server_sockets_.find(socket); iter != server_sockets_.end()) {
DestroyInternalSocket(iter);
}
}
void TurnServer::OnInternalPacket(AsyncPacketSocket* socket, const ReceivedIpPacket& packet) {
RTC_DCHECK_RUN_ON(thread_); // Fail if the packet is too small to even contain a channel header.
std::span<const uint8_t> payload = packet.payload(); if (payload.size() < TURN_CHANNEL_HEADER_SIZE) { return;
} auto iter = server_sockets_.find(socket);
RTC_DCHECK(iter != server_sockets_.end());
TurnServerConnection conn(packet.source_address(), iter->second, socket);
uint16_t msg_type = GetBE16(payload); if (!IsTurnChannelData(msg_type)) { // This is a STUN message.
HandleStunMessage(&conn, payload, packet.ecn());
} else { // This is a channel message; let the allocation handle it.
TurnServerAllocation* allocation = FindAllocation(&conn); if (allocation) {
allocation->HandleChannelData(payload, packet.ecn());
} if (stun_message_observer_ != nullptr) {
stun_message_observer_->ReceivedChannelData(payload);
}
}
}
// Look up the key that we'll use to validate the M-I. If we have an // existing allocation, the key will already be cached.
TurnServerAllocation* allocation = FindAllocation(conn);
std::string key; if (!allocation) {
GetKey(&msg, &key);
} else {
key = allocation->key();
}
// Ensure the message is authorized; only needed for requests. if (IsStunRequestType(msg.type())) { if (!CheckAuthorization(conn, &msg, key)) { return;
}
}
if (!allocation && msg.type() == STUN_ALLOCATE_REQUEST) {
HandleAllocateRequest(conn, &msg, key, ecn);
} elseif (allocation &&
(msg.type() != STUN_ALLOCATE_REQUEST ||
msg.transaction_id() == allocation->transaction_id())) { // This is a non-allocate request, or a retransmit of an allocate. // Check that the username matches the previous username used. if (IsStunRequestType(msg.type()) &&
msg.GetByteString(STUN_ATTR_USERNAME)->string_view() !=
allocation->username()) {
SendErrorResponse(conn, &msg, STUN_ERROR_WRONG_CREDENTIALS,
STUN_ERROR_REASON_WRONG_CREDENTIALS); return;
}
allocation->HandleTurnMessage(&msg, ecn);
} else { // Allocation mismatch.
SendErrorResponse(conn, &msg, STUN_ERROR_ALLOCATION_MISMATCH,
STUN_ERROR_REASON_ALLOCATION_MISMATCH);
}
}
// Fail if no MESSAGE_INTEGRITY. if (!mi_attr) {
SendErrorResponseWithRealmAndNonce(conn, msg, STUN_ERROR_UNAUTHORIZED,
STUN_ERROR_REASON_UNAUTHORIZED); returnfalse;
}
// Fail if there is MESSAGE_INTEGRITY but no username, nonce, or realm. if (!username_attr || !realm_attr || !nonce_attr) {
SendErrorResponse(conn, msg, STUN_ERROR_BAD_REQUEST,
STUN_ERROR_REASON_BAD_REQUEST); returnfalse;
}
// Fail if bad nonce. if (!ValidateNonce(nonce_attr->string_view())) {
SendErrorResponseWithRealmAndNonce(conn, msg, STUN_ERROR_STALE_NONCE,
STUN_ERROR_REASON_STALE_NONCE); returnfalse;
}
// Fail if bad MESSAGE_INTEGRITY. if (key.empty() || msg->ValidateMessageIntegrity(std::string(key)) !=
StunMessage::IntegrityStatus::kIntegrityOk) {
SendErrorResponseWithRealmAndNonce(conn, msg, STUN_ERROR_UNAUTHORIZED,
STUN_ERROR_REASON_UNAUTHORIZED); returnfalse;
}
// Fail if one-time-use nonce feature is enabled.
TurnServerAllocation* allocation = FindAllocation(conn); if (enable_otu_nonce_ && allocation &&
allocation->last_nonce() == nonce_attr->string_view()) {
SendErrorResponseWithRealmAndNonce(conn, msg, STUN_ERROR_STALE_NONCE,
STUN_ERROR_REASON_STALE_NONCE); returnfalse;
}
if (allocation) {
allocation->set_last_nonce(nonce_attr->string_view());
} // Success. return true;
}
void TurnServer::HandleBindingRequest(TurnServerConnection* conn, const StunMessage* req) {
StunMessage response(GetStunSuccessResponseTypeOrZero(*req),
req->transaction_id()); // Tell the user the address that we received their request from. auto mapped_addr_attr = std::make_unique<StunXorAddressAttribute>(
STUN_ATTR_XOR_MAPPED_ADDRESS, conn->src());
response.AddAttribute(std::move(mapped_addr_attr));
SendStun(conn, &response, EcnMarking::kNotEct);
}
void TurnServer::HandleAllocateRequest(TurnServerConnection* conn, const TurnMessage* msg,
absl::string_view key,
EcnMarking ecn) { // Check the parameters in the request. const StunUInt32Attribute* transport_attr =
msg->GetUInt32(STUN_ATTR_REQUESTED_TRANSPORT); if (!transport_attr) {
SendErrorResponse(conn, msg, STUN_ERROR_BAD_REQUEST,
STUN_ERROR_REASON_BAD_REQUEST); return;
}
// Only UDP is supported right now. int proto = transport_attr->value() >> 24; if (proto != IPPROTO_UDP) {
SendErrorResponse(conn, msg, STUN_ERROR_UNSUPPORTED_PROTOCOL,
STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL); return;
}
// Create the allocation and let it send the success response. // If the actual socket allocation fails, send an internal error.
TurnServerAllocation* alloc = CreateAllocation(conn, proto, key); if (alloc) {
alloc->HandleTurnMessage(msg, ecn);
} else {
SendErrorResponse(conn, msg, STUN_ERROR_SERVER_ERROR, "Failed to allocate socket");
}
}
std::string TurnServer::GenerateNonce(int64_t now) const { // Generate a nonce of the form hex(now + HMAC-MD5(nonce_key_, now))
std::string input(reinterpret_cast<constchar*>(&now), sizeof(now));
std::string nonce = hex_encode(input);
nonce += ComputeHmac(DIGEST_MD5, nonce_key_, input);
RTC_DCHECK(nonce.size() == kNonceSize);
return nonce;
}
bool TurnServer::ValidateNonce(absl::string_view nonce) const { // Check the size. if (nonce.size() != kNonceSize) { returnfalse;
}
// Decode the timestamp.
int64_t then; char* p = reinterpret_cast<char*>(&then);
size_t len = hex_decode(std::span<char>(p, sizeof(then)),
nonce.substr(0, sizeof(then) * 2)); if (len != sizeof(then)) { returnfalse;
}
// Verify the HMAC. if (nonce.substr(sizeof(then) * 2) !=
ComputeHmac(DIGEST_MD5, nonce_key_, std::string(p, sizeof(then)))) { returnfalse;
}
void TurnServer::Send(TurnServerConnection* conn, const ByteBufferWriter& buf,
EcnMarking ecn) {
RTC_DCHECK_RUN_ON(thread_);
AsyncSocketPacketOptions options; // TODO: bugs.webrtc.org/453581251 - If we want to properly test with TURN, // the server must copy `ecn`.
RTC_LOG_IF(LS_WARNING, ecn == EcnMarking::kCe)
<< "TurnServer does not properly support forwarding " "ECN.";
options.ect_1 = (ecn == EcnMarking::kEct1);
conn->socket()->SendTo(buf.Data(), buf.Length(), conn->src(), options);
}
void TurnServer::DestroyAllocation(TurnServerAllocation* allocation) { // Removing the internal socket if the connection is not udp.
AsyncPacketSocket* socket = allocation->conn()->socket(); auto iter = server_sockets_.find(socket); // Skip if the socket serving this allocation is UDP, as this will be shared // by all allocations. // Note: We may not find a socket if it's a TCP socket that was closed, and // the allocation is only now timing out. if (iter != server_sockets_.end() && iter->second != PROTO_UDP) {
DestroyInternalSocket(iter);
}
allocations_.erase(*(allocation->conn()));
}
void TurnServer::DestroyInternalSocket(ServerSocketMap::iterator iter) {
RTC_DCHECK(iter != server_sockets_.end()); auto node = server_sockets_.extract(iter);
AsyncPacketSocket* server_socket = node.key().get();
server_socket->UnsubscribeCloseEvent(this);
server_socket->DeregisterReceivedPacketCallback(); // We must destroy the socket async to avoid invalidating the callback list // iterator. (In other words, deleting an object from within a callback from // that object).
thread_->PostTask([node = std::move(node)] {});
}
void TurnServerAllocation::HandleTurnMessage(const TurnMessage* msg,
EcnMarking ecn) {
RTC_DCHECK_RUN_ON(thread_);
RTC_DCHECK(msg != nullptr); switch (msg->type()) { case STUN_ALLOCATE_REQUEST:
HandleAllocateRequest(msg); break; case TURN_REFRESH_REQUEST:
HandleRefreshRequest(msg); break; case TURN_SEND_INDICATION:
HandleSendIndication(msg, ecn); break; case TURN_CREATE_PERMISSION_REQUEST:
HandleCreatePermissionRequest(msg); break; case TURN_CHANNEL_BIND_REQUEST:
HandleChannelBindRequest(msg); break; default: // Not sure what to do with this, just eat it.
RTC_LOG(LS_WARNING) << ToString()
<< ": Invalid TURN message type received: "
<< msg->type();
}
}
void TurnServerAllocation::HandleAllocateRequest(const TurnMessage* msg) { // Copy the important info from the allocate request.
transaction_id_ = msg->transaction_id(); const StunByteStringAttribute* username_attr =
msg->GetByteString(STUN_ATTR_USERNAME);
RTC_DCHECK(username_attr != nullptr);
username_ = std::string(username_attr->string_view());
// Figure out the lifetime and start the allocation timer.
TimeDelta lifetime = ComputeLifetime(*msg);
PostDeleteSelf(lifetime);
RTC_LOG(LS_INFO) << ToString() << ": Created allocation with lifetime="
<< lifetime.seconds();
// We've already validated all the important bits; just send a response here.
TurnMessage response(GetStunSuccessResponseTypeOrZero(*msg),
msg->transaction_id());
auto mapped_addr_attr = std::make_unique<StunXorAddressAttribute>(
STUN_ATTR_XOR_MAPPED_ADDRESS, conn_.src()); auto relayed_addr_attr = std::make_unique<StunXorAddressAttribute>(
STUN_ATTR_XOR_RELAYED_ADDRESS, external_socket_->GetLocalAddress()); auto lifetime_attr = std::make_unique<StunUInt32Attribute>(
STUN_ATTR_LIFETIME, lifetime.seconds());
response.AddAttribute(std::move(mapped_addr_attr));
response.AddAttribute(std::move(relayed_addr_attr));
response.AddAttribute(std::move(lifetime_attr));
SendResponse(&response);
}
void TurnServerAllocation::HandleRefreshRequest(const TurnMessage* msg) { // Figure out the new lifetime.
TimeDelta lifetime = ComputeLifetime(*msg);
// Reset the expiration timer.
safety_.reset();
PostDeleteSelf(lifetime);
// If a permission exists, send the data on to the peer. if (HasPermission(peer_attr->GetAddress().ipaddr())) {
SendExternal(reinterpret_cast<char*>(data_attr->array_view().data()),
data_attr->length(), peer_attr->GetAddress(), ecn);
} else {
RTC_LOG(LS_WARNING) << ToString()
<< ": Received send indication without permission" " peer="
<< peer_attr->GetAddress().ToSensitiveString();
}
}
// Check that channel id is valid.
uint16_t channel_id = static_cast<uint16_t>(channel_attr->value() >> 16); if (channel_id < kMinTurnChannelNumber ||
channel_id > kMaxTurnChannelNumber) {
SendBadRequestResponse(msg); return;
}
// Check that this channel id isn't bound to another transport address, and // that this transport address isn't bound to another channel id. auto channel1 = FindChannel(channel_id); auto channel2 = FindChannel(peer_attr->GetAddress()); if (channel1 != channel2) {
SendBadRequestResponse(msg); return;
}
// Send a success response.
TurnMessage response(GetStunSuccessResponseTypeOrZero(*msg),
msg->transaction_id());
SendResponse(&response);
}
void TurnServerAllocation::HandleChannelData(std::span<const uint8_t> payload,
EcnMarking ecn) { // Extract the channel number from the data.
uint16_t channel_id = GetBE16(payload); auto channel = FindChannel(channel_id); if (channel != channels_.end()) { // Send the data to the peer address.
SendExternal(payload.data() + TURN_CHANNEL_HEADER_SIZE,
payload.size() - TURN_CHANNEL_HEADER_SIZE, channel->peer, ecn);
} else {
RTC_LOG(LS_WARNING) << ToString()
<< ": Received channel data for invalid channel, id="
<< channel_id;
}
}
void TurnServerAllocation::OnExternalPacket(AsyncPacketSocket* socket, const ReceivedIpPacket& packet) {
RTC_DCHECK(external_socket_.get() == socket); auto channel = FindChannel(packet.source_address()); if (channel != channels_.end()) { // There is a channel bound to this address. Send as a channel message.
ByteBufferWriter buf;
buf.WriteUInt16(channel->id);
buf.WriteUInt16(static_cast<uint16_t>(packet.payload().size()));
buf.Write(std::span<const uint8_t>(packet.payload()));
server_->Send(&conn_, buf, packet.ecn());
} elseif (!server_->enable_permission_checks_ ||
HasPermission(packet.source_address().ipaddr())) { // No channel, but a permission exists. Send as a data indication.
TurnMessage msg(TURN_DATA_INDICATION);
msg.AddAttribute(std::make_unique<StunXorAddressAttribute>(
STUN_ATTR_XOR_PEER_ADDRESS, packet.source_address()));
msg.AddAttribute(std::make_unique<StunByteStringAttribute>(
STUN_ATTR_DATA, packet.payload()));
server_->SendStun(&conn_, &msg, packet.ecn());
} else {
RTC_LOG(LS_WARNING)
<< ToString() << ": Received external packet without permission, peer="
<< packet.source_address().ToSensitiveString();
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.