1 /*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "p2p/base/stun_server.h"
12
13 #include <utility>
14
15 #include "rtc_base/byte_buffer.h"
16 #include "rtc_base/logging.h"
17
18 namespace cricket {
19
StunServer(rtc::AsyncUDPSocket * socket)20 StunServer::StunServer(rtc::AsyncUDPSocket* socket) : socket_(socket) {
21 socket_->SignalReadPacket.connect(this, &StunServer::OnPacket);
22 }
23
~StunServer()24 StunServer::~StunServer() {
25 socket_->SignalReadPacket.disconnect(this);
26 }
27
OnPacket(rtc::AsyncPacketSocket * socket,const char * buf,size_t size,const rtc::SocketAddress & remote_addr,const int64_t &)28 void StunServer::OnPacket(rtc::AsyncPacketSocket* socket,
29 const char* buf,
30 size_t size,
31 const rtc::SocketAddress& remote_addr,
32 const int64_t& /* packet_time_us */) {
33 // Parse the STUN message; eat any messages that fail to parse.
34 rtc::ByteBufferReader bbuf(buf, size);
35 StunMessage msg;
36 if (!msg.Read(&bbuf)) {
37 return;
38 }
39
40 // TODO(?): If unknown non-optional (<= 0x7fff) attributes are found, send a
41 // 420 "Unknown Attribute" response.
42
43 // Send the message to the appropriate handler function.
44 switch (msg.type()) {
45 case STUN_BINDING_REQUEST:
46 OnBindingRequest(&msg, remote_addr);
47 break;
48
49 default:
50 SendErrorResponse(msg, remote_addr, 600, "Operation Not Supported");
51 }
52 }
53
OnBindingRequest(StunMessage * msg,const rtc::SocketAddress & remote_addr)54 void StunServer::OnBindingRequest(StunMessage* msg,
55 const rtc::SocketAddress& remote_addr) {
56 StunMessage response;
57 GetStunBindResponse(msg, remote_addr, &response);
58 SendResponse(response, remote_addr);
59 }
60
SendErrorResponse(const StunMessage & msg,const rtc::SocketAddress & addr,int error_code,const char * error_desc)61 void StunServer::SendErrorResponse(const StunMessage& msg,
62 const rtc::SocketAddress& addr,
63 int error_code,
64 const char* error_desc) {
65 StunMessage err_msg;
66 err_msg.SetType(GetStunErrorResponseType(msg.type()));
67 err_msg.SetTransactionID(msg.transaction_id());
68
69 auto err_code = StunAttribute::CreateErrorCode();
70 err_code->SetCode(error_code);
71 err_code->SetReason(error_desc);
72 err_msg.AddAttribute(std::move(err_code));
73
74 SendResponse(err_msg, addr);
75 }
76
SendResponse(const StunMessage & msg,const rtc::SocketAddress & addr)77 void StunServer::SendResponse(const StunMessage& msg,
78 const rtc::SocketAddress& addr) {
79 rtc::ByteBufferWriter buf;
80 msg.Write(&buf);
81 rtc::PacketOptions options;
82 if (socket_->SendTo(buf.Data(), buf.Length(), addr, options) < 0)
83 RTC_LOG_ERR(LS_ERROR) << "sendto";
84 }
85
GetStunBindResponse(StunMessage * request,const rtc::SocketAddress & remote_addr,StunMessage * response) const86 void StunServer::GetStunBindResponse(StunMessage* request,
87 const rtc::SocketAddress& remote_addr,
88 StunMessage* response) const {
89 response->SetType(STUN_BINDING_RESPONSE);
90 response->SetTransactionID(request->transaction_id());
91
92 // Tell the user the address that we received their request from.
93 std::unique_ptr<StunAddressAttribute> mapped_addr;
94 if (request->IsLegacy()) {
95 mapped_addr = StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
96 } else {
97 mapped_addr = StunAttribute::CreateXorAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
98 }
99 mapped_addr->SetAddress(remote_addr);
100 response->AddAttribute(std::move(mapped_addr));
101 }
102
103 } // namespace cricket
104