11391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen/*
21391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen * libjingle
31391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen * Copyright 2004--2005, Google Inc.
41391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen *
51391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen * Redistribution and use in source and binary forms, with or without
61391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen * modification, are permitted provided that the following conditions are met:
71391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen *
81391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen *  1. Redistributions of source code must retain the above copyright notice,
91391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen *     this list of conditions and the following disclaimer.
101391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen *  2. Redistributions in binary form must reproduce the above copyright notice,
111391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen *     this list of conditions and the following disclaimer in the documentation
121391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen *     and/or other materials provided with the distribution.
131391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen *  3. The name of the author may not be used to endorse or promote products
141391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen *     derived from this software without specific prior written permission.
151391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen *
161391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
171391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
181391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
191391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
201391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
211391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
221391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
231391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
241391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
251391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
261391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen */
271391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
281391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen#ifdef POSIX
291391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen#include <errno.h>
301391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen#endif  // POSIX
311391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
321391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen#include "talk/p2p/base/stunserver.h"
331391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen#include "talk/base/bytebuffer.h"
341391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen#include "talk/base/logging.h"
351391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
361391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsennamespace cricket {
371391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
381391b24619d56bae6ce14bb54ed0fb16a945e853Kristian MonsenStunServer::StunServer(talk_base::AsyncUDPSocket* socket) : socket_(socket) {
391391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  socket_->SignalReadPacket.connect(this, &StunServer::OnPacket);
401391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen}
411391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
421391b24619d56bae6ce14bb54ed0fb16a945e853Kristian MonsenStunServer::~StunServer() {
431391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  socket_->SignalReadPacket.disconnect(this);
441391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen}
451391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
461391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsenvoid StunServer::OnPacket(
47dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    talk_base::AsyncPacketSocket* socket, const char* buf, size_t size,
48dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    const talk_base::SocketAddress& remote_addr) {
491391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
501391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  // TODO: If appropriate, look for the magic cookie before parsing.
511391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
521391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  // Parse the STUN message.
531391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  talk_base::ByteBuffer bbuf(buf, size);
541391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  StunMessage msg;
551391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  if (!msg.Read(&bbuf)) {
561391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen    SendErrorResponse(msg, remote_addr, 400, "Bad Request");
571391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen    return;
581391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  }
591391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
601391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  // TODO: If this is UDP, then we shouldn't allow non-fully-parsed messages.
611391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
621391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  // TODO: If unknown non-optiional (<= 0x7fff) attributes are found, send a
631391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  //       420 "Unknown Attribute" response.
641391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
651391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  // TODO: Check that a message-integrity attribute was given (or send 401
661391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  //       "Unauthorized").  Check that a username attribute was given (or send
671391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  //       432 "Missing Username").  Look up the username and password.  If it
681391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  //       is missing or the HMAC is wrong, send 431 "Integrity Check Failure".
691391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
701391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  // Send the message to the appropriate handler function.
711391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  switch (msg.type()) {
721391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  case STUN_BINDING_REQUEST:
731391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen    OnBindingRequest(&msg, remote_addr);
741391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen    return;
751391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
761391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  case STUN_ALLOCATE_REQUEST:
771391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen    OnAllocateRequest(&msg, remote_addr);
781391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen    return;
791391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
801391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  default:
811391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen    SendErrorResponse(msg, remote_addr, 600, "Operation Not Supported");
821391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  }
831391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen}
841391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
851391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsenvoid StunServer::OnBindingRequest(
861391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen    StunMessage* msg, const talk_base::SocketAddress& remote_addr) {
871391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  StunMessage response;
881391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  response.SetType(STUN_BINDING_RESPONSE);
891391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  response.SetTransactionID(msg->transaction_id());
901391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
911391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  // Tell the user the address that we received their request from.
921391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  StunAddressAttribute* mapped_addr =
931391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen      StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
941391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  mapped_addr->SetFamily(1);
951391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  mapped_addr->SetPort(remote_addr.port());
961391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  mapped_addr->SetIP(remote_addr.ip());
971391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  response.AddAttribute(mapped_addr);
981391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
991391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  // Tell the user the address that we are sending the response from.
100dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // This method should not be called if socket address is not
101dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // allocated yet.
102dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  bool allocated;
103dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  talk_base::SocketAddress local_addr = socket_->GetLocalAddress(&allocated);
104dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  ASSERT(allocated);
105dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1061391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  StunAddressAttribute* source_addr =
1071391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen      StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS);
1081391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  source_addr->SetFamily(1);
1091391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  source_addr->SetPort(local_addr.port());
1101391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  source_addr->SetIP(local_addr.ip());
1111391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  response.AddAttribute(source_addr);
1121391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
1131391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  // TODO: Add username and message-integrity.
1141391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
1151391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  // TODO: Add changed-address.  (Keep information about three other servers.)
1161391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
1171391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  SendResponse(response, remote_addr);
1181391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen}
1191391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
1201391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsenvoid StunServer::OnAllocateRequest(
1211391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen    StunMessage* msg, const talk_base::SocketAddress& addr) {
1221391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  SendErrorResponse(*msg, addr, 600, "Operation Not Supported");
1231391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen}
1241391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
1251391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsenvoid StunServer::OnSharedSecretRequest(
1261391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen    StunMessage* msg, const talk_base::SocketAddress& addr) {
1271391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  SendErrorResponse(*msg, addr, 600, "Operation Not Supported");
1281391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen}
1291391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
1301391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsenvoid StunServer::OnSendRequest(StunMessage* msg,
1311391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen                               const talk_base::SocketAddress& addr) {
1321391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  SendErrorResponse(*msg, addr, 600, "Operation Not Supported");
1331391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen}
1341391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
1351391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsenvoid StunServer::SendErrorResponse(
1361391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen    const StunMessage& msg, const talk_base::SocketAddress& addr,
1371391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen    int error_code, const char* error_desc) {
1381391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
1391391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  StunMessage err_msg;
1401391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  err_msg.SetType(GetStunErrorResponseType(msg.type()));
1411391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  err_msg.SetTransactionID(msg.transaction_id());
1421391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
1431391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  StunErrorCodeAttribute* err_code = StunAttribute::CreateErrorCode();
1441391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  err_code->SetErrorClass(error_code / 100);
1451391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  err_code->SetNumber(error_code % 100);
1461391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  err_code->SetReason(error_desc);
1471391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  err_msg.AddAttribute(err_code);
1481391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
1491391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  SendResponse(err_msg, addr);
1501391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen}
1511391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
1521391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsenvoid StunServer::SendResponse(
1531391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen    const StunMessage& msg, const talk_base::SocketAddress& addr) {
1541391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
1551391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  talk_base::ByteBuffer buf;
1561391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  msg.Write(&buf);
1571391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
1581391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  // TODO: Allow response addr attribute if sent from another stun server.
1591391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
1601391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen  if (socket_->SendTo(buf.Data(), buf.Length(), addr) < 0)
1611391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen    LOG_ERR(LS_ERROR) << "sendto";
1621391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen}
1631391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen
1641391b24619d56bae6ce14bb54ed0fb16a945e853Kristian Monsen}  // namespace cricket
165