1/*
2 * libjingle
3 * Copyright 2004--2005, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 *  1. Redistributions of source code must retain the above copyright notice,
9 *     this list of conditions and the following disclaimer.
10 *  2. Redistributions in binary form must reproduce the above copyright notice,
11 *     this list of conditions and the following disclaimer in the documentation
12 *     and/or other materials provided with the distribution.
13 *  3. The name of the author may not be used to endorse or promote products
14 *     derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#ifdef POSIX
29#include <errno.h>
30#endif  // POSIX
31
32#include "talk/p2p/base/stunserver.h"
33#include "talk/base/bytebuffer.h"
34#include "talk/base/logging.h"
35
36namespace cricket {
37
38StunServer::StunServer(talk_base::AsyncUDPSocket* socket) : socket_(socket) {
39  socket_->SignalReadPacket.connect(this, &StunServer::OnPacket);
40}
41
42StunServer::~StunServer() {
43  socket_->SignalReadPacket.disconnect(this);
44}
45
46void StunServer::OnPacket(
47    talk_base::AsyncPacketSocket* socket, const char* buf, size_t size,
48    const talk_base::SocketAddress& remote_addr) {
49
50  // TODO: If appropriate, look for the magic cookie before parsing.
51
52  // Parse the STUN message.
53  talk_base::ByteBuffer bbuf(buf, size);
54  StunMessage msg;
55  if (!msg.Read(&bbuf)) {
56    SendErrorResponse(msg, remote_addr, 400, "Bad Request");
57    return;
58  }
59
60  // TODO: If this is UDP, then we shouldn't allow non-fully-parsed messages.
61
62  // TODO: If unknown non-optiional (<= 0x7fff) attributes are found, send a
63  //       420 "Unknown Attribute" response.
64
65  // TODO: Check that a message-integrity attribute was given (or send 401
66  //       "Unauthorized").  Check that a username attribute was given (or send
67  //       432 "Missing Username").  Look up the username and password.  If it
68  //       is missing or the HMAC is wrong, send 431 "Integrity Check Failure".
69
70  // Send the message to the appropriate handler function.
71  switch (msg.type()) {
72  case STUN_BINDING_REQUEST:
73    OnBindingRequest(&msg, remote_addr);
74    return;
75
76  case STUN_ALLOCATE_REQUEST:
77    OnAllocateRequest(&msg, remote_addr);
78    return;
79
80  default:
81    SendErrorResponse(msg, remote_addr, 600, "Operation Not Supported");
82  }
83}
84
85void StunServer::OnBindingRequest(
86    StunMessage* msg, const talk_base::SocketAddress& remote_addr) {
87  StunMessage response;
88  response.SetType(STUN_BINDING_RESPONSE);
89  response.SetTransactionID(msg->transaction_id());
90
91  // Tell the user the address that we received their request from.
92  StunAddressAttribute* mapped_addr =
93      StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
94  mapped_addr->SetFamily(1);
95  mapped_addr->SetPort(remote_addr.port());
96  mapped_addr->SetIP(remote_addr.ip());
97  response.AddAttribute(mapped_addr);
98
99  // Tell the user the address that we are sending the response from.
100  // This method should not be called if socket address is not
101  // allocated yet.
102  bool allocated;
103  talk_base::SocketAddress local_addr = socket_->GetLocalAddress(&allocated);
104  ASSERT(allocated);
105
106  StunAddressAttribute* source_addr =
107      StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS);
108  source_addr->SetFamily(1);
109  source_addr->SetPort(local_addr.port());
110  source_addr->SetIP(local_addr.ip());
111  response.AddAttribute(source_addr);
112
113  // TODO: Add username and message-integrity.
114
115  // TODO: Add changed-address.  (Keep information about three other servers.)
116
117  SendResponse(response, remote_addr);
118}
119
120void StunServer::OnAllocateRequest(
121    StunMessage* msg, const talk_base::SocketAddress& addr) {
122  SendErrorResponse(*msg, addr, 600, "Operation Not Supported");
123}
124
125void StunServer::OnSharedSecretRequest(
126    StunMessage* msg, const talk_base::SocketAddress& addr) {
127  SendErrorResponse(*msg, addr, 600, "Operation Not Supported");
128}
129
130void StunServer::OnSendRequest(StunMessage* msg,
131                               const talk_base::SocketAddress& addr) {
132  SendErrorResponse(*msg, addr, 600, "Operation Not Supported");
133}
134
135void StunServer::SendErrorResponse(
136    const StunMessage& msg, const talk_base::SocketAddress& addr,
137    int error_code, const char* error_desc) {
138
139  StunMessage err_msg;
140  err_msg.SetType(GetStunErrorResponseType(msg.type()));
141  err_msg.SetTransactionID(msg.transaction_id());
142
143  StunErrorCodeAttribute* err_code = StunAttribute::CreateErrorCode();
144  err_code->SetErrorClass(error_code / 100);
145  err_code->SetNumber(error_code % 100);
146  err_code->SetReason(error_desc);
147  err_msg.AddAttribute(err_code);
148
149  SendResponse(err_msg, addr);
150}
151
152void StunServer::SendResponse(
153    const StunMessage& msg, const talk_base::SocketAddress& addr) {
154
155  talk_base::ByteBuffer buf;
156  msg.Write(&buf);
157
158  // TODO: Allow response addr attribute if sent from another stun server.
159
160  if (socket_->SendTo(buf.Data(), buf.Length(), addr) < 0)
161    LOG_ERR(LS_ERROR) << "sendto";
162}
163
164}  // namespace cricket
165