示例#1
0
// this is the code for doing a SET-ACTIVE-DESTINATION, but it's
// got a bogus SendIndication->DataIndication pair in there that
// needs to be removed
int
nr_turn_client_set_active_destination(nr_turn_client_ctx *ctx, nr_transport_addr *remote_addr, NR_async_cb finished_cb, void *cb_arg)
{
    int r,_status;
    nr_stun_client_set_active_dest_request_params    *set_active_dest_request;

    if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED)
        ABORT(R_NOT_PERMITTED);

    assert(ctx->phase == NR_TURN_CLIENT_PHASE_ALLOCATE_REQUEST2);

    set_active_dest_request = &ctx->stun_ctx[NR_TURN_CLIENT_PHASE_SET_ACTIVE_DESTINATION]->params.set_active_dest_request;

    ctx->finished_cb=finished_cb;
    ctx->cb_arg=cb_arg;

    if ((r=nr_transport_addr_copy(&set_active_dest_request->remote_addr, remote_addr)))
        ABORT(r);

    _status=0;
  abort:
    if (_status)
        ctx->state = NR_TURN_CLIENT_STATE_FAILED;
    if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED) {
        ctx->finished_cb = 0;  /* prevent 2nd call */
        /* finished_cb call must be absolutely last thing in function
         * because as a side effect this ctx may be operated on in the
         * callback */
        finished_cb(0,0,cb_arg);
    }

    return(_status);
}
示例#2
0
RefPtr<NrSocketBase> TestNrSocket::create_external_socket(
    const nr_transport_addr &dest_addr) const {
  MOZ_ASSERT(nat_->enabled_);
  MOZ_ASSERT(!nat_->is_an_internal_tuple(dest_addr));

  int r;
  nr_transport_addr nat_external_addr;

  // Open the socket on an arbitrary port, on the same address.
  // TODO(bug 1170299): Remove const_cast when no longer necessary
  if ((r = nr_transport_addr_copy(
             &nat_external_addr,
             const_cast<nr_transport_addr*>(&internal_socket_->my_addr())))) {
    r_log(LOG_GENERIC,LOG_CRIT, "%s: Failure in nr_transport_addr_copy: %d",
                                __FUNCTION__, r);
    return nullptr;
  }

  if ((r = nr_transport_addr_set_port(&nat_external_addr, 0))) {
    r_log(LOG_GENERIC,LOG_CRIT, "%s: Failure in nr_transport_addr_set_port: %d",
                                __FUNCTION__, r);
    return nullptr;
  }

  RefPtr<NrSocketBase> external_socket;
  r = NrSocketBase::CreateSocket(&nat_external_addr, &external_socket);

  if (r) {
    r_log(LOG_GENERIC,LOG_CRIT, "%s: Failure in NrSocket::create: %d",
                                __FUNCTION__, r);
    return nullptr;
  }

  return external_socket;
}
示例#3
0
/* TODO([email protected]): We currently don't support channels.
   We might in the future. Mozilla bug 857736 */
int nr_turn_client_send_indication(nr_turn_client_ctx *ctx,
                                   const UCHAR *msg, size_t len,
                                   int flags, nr_transport_addr *remote_addr)
{
  int r,_status;
  nr_stun_client_send_indication_params params = { { 0 } };
  nr_stun_message *ind = 0;

  if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED)
    ABORT(R_FAILED);

  r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Send indication len=%zu",
        ctx->label, len);

  if ((r=nr_turn_client_ensure_perm(ctx, remote_addr)))
    ABORT(r);

  if ((r=nr_transport_addr_copy(&params.remote_addr, remote_addr)))
    ABORT(r);

  params.data.data = (UCHAR*)msg;
  params.data.len = len;

  if ((r=nr_stun_build_send_indication(&params, &ind)))
    ABORT(r);

  if ((r=nr_turn_client_send_stun_request(ctx, ind, flags)))
    ABORT(r);

  _status=0;
abort:
  nr_stun_message_destroy(&ind);
  return(_status);
}
示例#4
0
TestNrSocket::PortMapping::PortMapping(
    const nr_transport_addr &remote_address,
    const RefPtr<NrSocketBase> &external_socket) :
  external_socket_(external_socket) {
  // TODO(bug 1170299): Remove const_cast when no longer necessary
  nr_transport_addr_copy(&remote_address_,
                         const_cast<nr_transport_addr*>(&remote_address));
}
// callback while UDP socket is opened or closed
NS_IMETHODIMP NrSocketIpc::CallListenerVoid(const nsACString &type) {
  ASSERT_ON_THREAD(main_thread_);
  if (type.EqualsLiteral("onopen")) {
    ReentrantMonitorAutoEnter mon(monitor_);

    uint16_t port;
    if (NS_FAILED(socket_child_->GetLocalPort(&port))) {
      err_ = true;
      MOZ_ASSERT(false, "Failed to get local port");
      return NS_OK;
    }

    nsAutoCString address;
    if(NS_FAILED(socket_child_->GetLocalAddress(address))) {
      err_ = true;
      MOZ_ASSERT(false, "Failed to get local address");
      return NS_OK;
    }

    PRNetAddr praddr;
    if (PR_SUCCESS != PR_InitializeNetAddr(PR_IpAddrAny, port, &praddr)) {
      err_ = true;
      MOZ_ASSERT(false, "Failed to set port in PRNetAddr");
      return NS_OK;
    }

    if (PR_SUCCESS != PR_StringToNetAddr(address.BeginReading(), &praddr)) {
      err_ = true;
      MOZ_ASSERT(false, "Failed to convert local host to PRNetAddr");
      return NS_OK;
    }

    nr_transport_addr expected_addr;
    if(nr_transport_addr_copy(&expected_addr, &my_addr_)) {
      err_ = true;
      MOZ_ASSERT(false, "Failed to copy my_addr_");
    }

    if (nr_praddr_to_transport_addr(&praddr, &my_addr_, 1)) {
      err_ = true;
      MOZ_ASSERT(false, "Failed to copy local host to my_addr_");
    }

    if (nr_transport_addr_cmp(&expected_addr, &my_addr_,
                              NR_TRANSPORT_ADDR_CMP_MODE_ADDR)) {
      err_ = true;
      MOZ_ASSERT(false, "Address of opened socket is not expected");
    }

    mon.NotifyAll();
  } else if (type.EqualsLiteral("onclose")) {
    // Already handled in UpdateReadyState, nothing to do here
  } else {
    MOZ_ASSERT(false, "Received unexpected event");
  }

  return NS_OK;
}
示例#6
0
// nr_socket public APIs
int NrSocketIpc::create(nr_transport_addr *addr) {
  ASSERT_ON_THREAD(sts_thread_);

  int r, _status;
  nsresult rv;
  int32_t port;
  nsCString host;

  ReentrantMonitorAutoEnter mon(monitor_);

  if (state_ != NR_INIT) {
    ABORT(R_INTERNAL);
  }

  // Bug 950660: Remote TCP socket is not supported yet.
  if (NS_WARN_IF(addr->protocol != IPPROTO_UDP)) {
    MOZ_ASSERT(false, "NrSocket over TCP is not e10s ready, see Bug 950660");
    ABORT(R_INTERNAL);
  }

  sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
  if (NS_FAILED(rv)) {
    MOZ_ASSERT(false, "Failed to get STS thread");
    ABORT(R_INTERNAL);
  }

  if ((r=nr_transport_addr_get_addrstring_and_port(addr, &host, &port))) {
    ABORT(r);
  }

  // wildcard address will be resolved at NrSocketIpc::CallListenerVoid
  if ((r=nr_transport_addr_copy(&my_addr_, addr))) {
    ABORT(r);
  }

  state_ = NR_CONNECTING;

  RUN_ON_THREAD(main_thread_,
                mozilla::WrapRunnable(nsRefPtr<NrSocketIpc>(this),
                                      &NrSocketIpc::create_m,
                                      host, static_cast<uint16_t>(port)),
                NS_DISPATCH_NORMAL);

  // Wait until socket creation complete.
  mon.Wait();

  if (err_) {
    ABORT(R_INTERNAL);
  }

  state_ = NR_CONNECTED;

  _status = 0;
abort:
  return(_status);
}
示例#7
0
static int nr_turn_permission_create(nr_turn_client_ctx *ctx, nr_transport_addr *addr,
                                     nr_turn_permission **permp)
{
  int r, _status;
  nr_turn_permission *perm = 0;

  assert(ctx->state == NR_TURN_CLIENT_STATE_ALLOCATED);

  r_log(NR_LOG_TURN, LOG_INFO, "TURN(%s): Creating permission for %s",
        ctx->label, addr->as_string);

  if (!(perm = RCALLOC(sizeof(nr_turn_permission))))
    ABORT(R_NO_MEMORY);

  if ((r=nr_transport_addr_copy(&perm->addr, addr)))
    ABORT(r);

  perm->last_used = 0;

  if ((r=nr_turn_stun_ctx_create(ctx, NR_TURN_CLIENT_MODE_PERMISSION_REQUEST,
                                 nr_turn_client_permissions_cb,
                                 nr_turn_client_permission_error_cb,
                                 &perm->stun)))
    ABORT(r);

  /* We want to authenticate on the first packet */
  if ((r=nr_turn_stun_set_auth_params(perm->stun, ctx->realm, ctx->nonce)))
    ABORT(r);

  if ((r=nr_transport_addr_copy(
          &perm->stun->stun->params.permission_request.remote_addr, addr)))
    ABORT(r);
  STAILQ_INSERT_TAIL(&ctx->permissions, perm, entry);

  *permp = perm;

  _status=0;
abort:
  if (_status) {
    nr_turn_permission_destroy(&perm);
  }
  return(_status);
}
示例#8
0
static void nr_turn_client_allocate_cb(NR_SOCKET s, int how, void *arg)
{
  nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
  nr_turn_stun_ctx *refresh_ctx;
  NR_async_cb tmp_finished_cb;
  int r,_status;

  ctx->tctx->state = NR_TURN_CLIENT_STATE_ALLOCATED;

  if ((r=nr_transport_addr_copy(
          &ctx->tctx->relay_addr,
          &ctx->stun->results.allocate_response.relay_addr)))
    ABORT(r);

  if ((r=nr_transport_addr_copy(
          &ctx->tctx->mapped_addr,
          &ctx->stun->results.allocate_response.mapped_addr)))
    ABORT(r);

  if ((r=nr_turn_client_refresh_setup(ctx->tctx, &refresh_ctx)))
    ABORT(r);

  if ((r=nr_turn_client_start_refresh_timer(
          ctx->tctx, refresh_ctx,
          ctx->stun->results.allocate_response.lifetime_secs)))
    ABORT(r);

  r_log(NR_LOG_TURN, LOG_INFO,
        "TURN(%s): Succesfully allocated addr %s lifetime=%u",
        ctx->tctx->label,
        ctx->tctx->relay_addr.as_string,
        ctx->stun->results.allocate_response.lifetime_secs);

  _status=0;
abort:
  if (_status) {
    nr_turn_client_failed(ctx->tctx);
  }
  tmp_finished_cb = ctx->tctx->finished_cb;
  ctx->tctx->finished_cb = 0;  /* So we don't call it again */
  tmp_finished_cb(0, 0, ctx->tctx->cb_arg);
}
示例#9
0
int NrSocketIpc::getaddr(nr_transport_addr *addrp) {
  ASSERT_ON_THREAD(sts_thread_);

  ReentrantMonitorAutoEnter mon(monitor_);

  if (state_ != NR_CONNECTED) {
    return R_INTERNAL;
  }

  return nr_transport_addr_copy(addrp, &my_addr_);
}
示例#10
0
/* nr_turn_client_ctx functions */
int nr_turn_client_ctx_create(const char *label, nr_socket *sock,
                              const char *username, Data *password,
                              nr_transport_addr *addr,
                              nr_turn_client_ctx **ctxp)
{
  nr_turn_client_ctx *ctx=0;
  int r,_status;

  if ((r=r_log_register("turn", &NR_LOG_TURN)))
    ABORT(r);

  if(!(ctx=RCALLOC(sizeof(nr_turn_client_ctx))))
    ABORT(R_NO_MEMORY);

  STAILQ_INIT(&ctx->stun_ctxs);
  STAILQ_INIT(&ctx->permissions);

  if(!(ctx->label=r_strdup(label)))
    ABORT(R_NO_MEMORY);

  ctx->sock=sock;
  ctx->username = r_strdup(username);
  if (!ctx->username)
    ABORT(R_NO_MEMORY);

  if ((r=r_data_create(&ctx->password, password->data, password->len)))
    ABORT(r);
  if ((r=nr_transport_addr_copy(&ctx->turn_server_addr, addr)))
    ABORT(r);

  if (addr->protocol == IPPROTO_UDP) {
    ctx->state = NR_TURN_CLIENT_STATE_CONNECTED;
  }
  else {
    assert(addr->protocol == IPPROTO_TCP);
    ctx->state = NR_TURN_CLIENT_STATE_INITTED;

    if (r=nr_turn_client_connect(ctx)) {
      if (r != R_WOULDBLOCK)
        ABORT(r);
    }
  }

  *ctxp=ctx;

  _status=0;
abort:
  if(_status){
    nr_turn_client_ctx_destroy(&ctx);
  }
  return(_status);
}
示例#11
0
// callback while UDP socket is opened
NS_IMETHODIMP NrSocketIpc::CallListenerOpened() {
  ASSERT_ON_THREAD(main_thread_);
  ReentrantMonitorAutoEnter mon(monitor_);

  uint16_t port;
  if (NS_FAILED(socket_child_->GetLocalPort(&port))) {
    err_ = true;
    MOZ_ASSERT(false, "Failed to get local port");
    return NS_OK;
  }

  nsAutoCString address;
  if(NS_FAILED(socket_child_->GetLocalAddress(address))) {
    err_ = true;
    MOZ_ASSERT(false, "Failed to get local address");
    return NS_OK;
  }

  PRNetAddr praddr;
  if (PR_SUCCESS != PR_InitializeNetAddr(PR_IpAddrAny, port, &praddr)) {
    err_ = true;
    MOZ_ASSERT(false, "Failed to set port in PRNetAddr");
    return NS_OK;
  }

  if (PR_SUCCESS != PR_StringToNetAddr(address.BeginReading(), &praddr)) {
    err_ = true;
    MOZ_ASSERT(false, "Failed to convert local host to PRNetAddr");
    return NS_OK;
  }

  nr_transport_addr expected_addr;
  if(nr_transport_addr_copy(&expected_addr, &my_addr_)) {
    err_ = true;
    MOZ_ASSERT(false, "Failed to copy my_addr_");
  }

  if (nr_praddr_to_transport_addr(&praddr, &my_addr_, IPPROTO_UDP, 1)) {
    err_ = true;
    MOZ_ASSERT(false, "Failed to copy local host to my_addr_");
  }

  if (nr_transport_addr_cmp(&expected_addr, &my_addr_,
                            NR_TRANSPORT_ADDR_CMP_MODE_ADDR)) {
    err_ = true;
    MOZ_ASSERT(false, "Address of opened socket is not expected");
  }

  mon.NotifyAll();

  return NS_OK;
}
示例#12
0
int nr_local_addr_copy(nr_local_addr *to, nr_local_addr *from)
  {
    int r,_status;

    if (r=nr_transport_addr_copy(&(to->addr), &(from->addr))) {
      ABORT(r);
    }
    to->interface = from->interface;

    _status=0;
  abort:
    return(_status);
  }
示例#13
0
int nr_turn_client_get_mapped_address(nr_turn_client_ctx *ctx,
                                       nr_transport_addr *mapped_address)
{
  int r, _status;

  if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED)
    ABORT(R_FAILED);

  if (r=nr_transport_addr_copy(mapped_address, &ctx->mapped_addr))
    ABORT(r);

  _status=0;
abort:
  return(_status);
}
示例#14
0
int nr_stun_client_ctx_create(char *label, nr_socket *sock, nr_transport_addr *peer, UINT4 RTO, nr_stun_client_ctx **ctxp)
{
    nr_stun_client_ctx *ctx=0;
    int r,_status;

    if ((r=nr_stun_startup()))
        ABORT(r);

    if(!(ctx=RCALLOC(sizeof(nr_stun_client_ctx))))
        ABORT(R_NO_MEMORY);

    ctx->state=NR_STUN_CLIENT_STATE_INITTED;

    if(!(ctx->label=r_strdup(label)))
        ABORT(R_NO_MEMORY);

    ctx->sock=sock;

    nr_socket_getaddr(sock,&ctx->my_addr);
    nr_transport_addr_copy(&ctx->peer_addr,peer);

    if (NR_reg_get_uint4(NR_STUN_REG_PREF_CLNT_RETRANSMIT_TIMEOUT, &ctx->rto_ms)) {
        if (RTO != 0)
            ctx->rto_ms = RTO;
        else
            ctx->rto_ms = 100;
    }

    if (NR_reg_get_double(NR_STUN_REG_PREF_CLNT_RETRANSMIT_BACKOFF, &ctx->retransmission_backoff_factor))
        ctx->retransmission_backoff_factor = 2.0;

    if (NR_reg_get_uint4(NR_STUN_REG_PREF_CLNT_MAXIMUM_TRANSMITS, &ctx->maximum_transmits))
        ctx->maximum_transmits = 7;

    if (NR_reg_get_uint4(NR_STUN_REG_PREF_CLNT_FINAL_RETRANSMIT_BACKOFF, &ctx->final_retransmit_backoff_ms))
        ctx->final_retransmit_backoff_ms = 16 * ctx->rto_ms;

    *ctxp=ctx;

    _status=0;
abort:
    if(_status) {
        nr_stun_client_ctx_destroy(&ctx);
    }
    return(_status);
}
示例#15
0
static int nr_tcp_socket_ctx_initialize(nr_tcp_socket_ctx *tcpsock,
  nr_transport_addr *addr, void* cb_arg)
  {
    int r, _status;
    NR_SOCKET fd;

    if ((r=nr_transport_addr_copy(&tcpsock->remote_addr, addr)))
      ABORT(r);
    if ((r=nr_socket_getfd(tcpsock->inner, &fd)))
      ABORT(r);
    NR_ASYNC_WAIT(fd, NR_ASYNC_WAIT_READ, nr_tcp_socket_readable_cb, cb_arg);

    _status=0;
  abort:
    if (_status)
      r_log(LOG_ICE,LOG_DEBUG,"%s:%d function %s(addr:%s) failed with error %d",__FILE__,__LINE__,__FUNCTION__,addr->as_string,_status);
    return(_status);
  }
示例#16
0
int
nr_turn_client_ctx_create(char *label, nr_socket *sock, nr_socket *wsock, nr_transport_addr *turn_server, UINT4 RTO, nr_turn_client_ctx **ctxp)
{
    nr_turn_client_ctx *ctx=0;
    int r,_status;
    int i;
    char string[256];

    if ((r=r_log_register("turn", &NR_LOG_TURN)))
      ABORT(r);

    if(!(ctx=RCALLOC(sizeof(nr_turn_client_ctx))))
      ABORT(R_NO_MEMORY);

    ctx->state=NR_TURN_CLIENT_STATE_INITTED;

    if(!(ctx->label=r_strdup(label)))
      ABORT(R_NO_MEMORY);

    ctx->sock=sock;
    ctx->wrapping_sock=wsock;

    ctx->phase=NR_TURN_CLIENT_PHASE_INITIALIZED;

    nr_transport_addr_copy(&ctx->turn_server_addr,turn_server);

    for (i = 0; i < NUMBER_OF_STUN_CTX; ++i) {
        snprintf(string, sizeof(string), "%s:%s", label, TURN_PHASE_LABEL[i]);

        if ((r=nr_stun_client_ctx_create(string, sock, turn_server, RTO, &ctx->stun_ctx[i]))) {
            r_log_nr(NR_LOG_TURN,LOG_ERR,r,"TURN(%s): Failed to start",string);
            ABORT(r);
        }
    }

    *ctxp=ctx;

    _status=0;
  abort:
    if(_status){
      nr_turn_client_ctx_destroy(&ctx);
    }
    return(_status);
}
示例#17
0
/* TODO([email protected]): We currently don't support channels.
   We might in the future. Mozilla bug 857736 */
int nr_turn_client_send_indication(nr_turn_client_ctx *ctx,
                                   const UCHAR *msg, size_t len,
                                   int flags, nr_transport_addr *remote_addr)
{
  int r,_status;
  nr_stun_client_send_indication_params params = { { 0 } };
  nr_stun_message *ind = 0;

  if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED)
    ABORT(R_FAILED);

  r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Send indication len=%zu",
        ctx->label, len);

  if ((r=nr_turn_client_ensure_perm(ctx, remote_addr)))
    ABORT(r);

  if ((r=nr_transport_addr_copy(&params.remote_addr, remote_addr)))
    ABORT(r);

  params.data.data = (UCHAR*)msg;
  params.data.len = len;

  if ((r=nr_stun_build_send_indication(&params, &ind)))
    ABORT(r);

  if ((r=nr_stun_encode_message(ind)))
    ABORT(r);

  if ((r=nr_socket_sendto(ctx->sock,
                          ind->buffer, ind->length, flags,
                          &ctx->turn_server_addr))) {
    r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): Failed sending send indication",
          ctx->label);
    ABORT(r);
  }

  _status=0;
abort:
  RFREE(ind);
  return(_status);
}
示例#18
0
int
nr_turn_client_rewrite_indication_data(UCHAR *msg, size_t len, size_t *newlen, nr_transport_addr *remote_addr)
{
    int _status;
#if 0
    int r,_status;
    nr_stun_message ind;

    if ((r=nr_stun_parse_message((char*)msg, len, &ind)))
        ABORT(r);

    if (ind.msgHdr.msgType != DataIndicationMsg)
        ABORT(R_BAD_ARGS);

    if (ind.hasRemoteAddress) {
        if ((r=nr_transport_addr_copy(remote_addr, &ind.remoteAddress)))
            ABORT(r);
    }
    else {
        ABORT(R_BAD_ARGS);
    }

    if (ind.hasData) {
        assert(ind.data.length < len);

        memmove(msg, ind.data.data, ind.data.length);
        msg[ind.data.length] = '\0';

        *newlen = ind.data.length;
    }
    else {
        *newlen = 0;
    }
#else
//TODO: what will this be turned into in the latest version of the spec???
ABORT(R_FAILED);
#endif

    _status=0;
  abort:
    return(_status);
}
示例#19
0
int nr_stun_client_restart(nr_stun_client_ctx *ctx)
  {
    int r,_status;
    int mode;
    NR_async_cb finished_cb;
    void *cb_arg;
    nr_stun_message_attribute *ec;
    nr_stun_message_attribute *as;

    if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING)
        ABORT(R_NOT_PERMITTED);

    assert(ctx->retry_ct <= 2);
    if (ctx->retry_ct > 2)
        ABORT(R_NOT_PERMITTED);

    ++ctx->retry_ct;

    mode = ctx->mode;
    finished_cb = ctx->finished_cb;
    cb_arg = ctx->cb_arg;

    if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_ERROR_CODE, &ec)
     && ec->u.error_code.number == 300) {
        if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_ALTERNATE_SERVER, &as)) {
            nr_transport_addr_copy(&ctx->peer_addr, &as->u.alternate_server);
        }
    }

    nr_stun_client_reset(ctx);

    if (r=nr_stun_client_start(ctx, mode, finished_cb, cb_arg))
      ABORT(r);

    _status=0;
  abort:
    return(_status);
  }
示例#20
0
int
nr_turn_client_relay_indication_data(nr_socket *sock, const UCHAR *msg, size_t len, int flags, nr_transport_addr *relay_addr, nr_transport_addr *remote_addr)
{
    int r,_status;
    nr_stun_client_send_indication_params params = { { 0 } };
    nr_stun_message *ind = 0;

    if ((r=nr_transport_addr_copy(&params.remote_addr, remote_addr)))
        ABORT(r);

    params.data.data = (UCHAR*)msg;
    params.data.len = len;
 
    if ((r=nr_stun_build_send_indication(&params, &ind)))
        ABORT(r);

    if ((r=nr_socket_sendto(sock, ind->buffer, ind->length, flags, relay_addr)))
        ABORT(r);

    _status=0;
  abort:
    RFREE(ind);
    return(_status);
}
示例#21
0
static void nr_ice_candidate_pair_stun_cb(NR_SOCKET s, int how, void *cb_arg)
  {
    int r,_status;
    nr_ice_cand_pair *pair=cb_arg,*orig_pair;
    nr_ice_candidate *cand=0;
    nr_stun_message *sres;
    nr_transport_addr *request_src;
    nr_transport_addr *request_dst;
    nr_transport_addr *response_src;
    nr_transport_addr response_dst;
    nr_stun_message_attribute *attr;

    pair->stun_cb_timer=0;

    r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/CAND-PAIR(%s): STUN cb on pair addr = %s",
      pair->pctx->label,pair->local->stream->label,pair->codeword,pair->as_string);

    /* This ordinarily shouldn't happen, but can if we're
       doing the second check to confirm nomination.
       Just bail out */
    if(pair->state==NR_ICE_PAIR_STATE_SUCCEEDED)
      goto done;

    switch(pair->stun_client->state){
      case NR_STUN_CLIENT_STATE_FAILED:
        sres=pair->stun_client->response;
        if(sres && nr_stun_message_has_attribute(sres,NR_STUN_ATTR_ERROR_CODE,&attr)&&attr->u.error_code.number==487){

          /*
           * Flip the controlling bit; subsequent 487s for other pairs will be
           * ignored, since we abandon their STUN transactions.
           */
          nr_ice_peer_ctx_switch_controlling_role(pair->pctx);

          return;
        }
        /* Fall through */
      case NR_STUN_CLIENT_STATE_TIMED_OUT:
        nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FAILED);
        break;
      case NR_STUN_CLIENT_STATE_DONE:
        /* make sure the addresses match up S 7.1.2.2 */
        response_src=&pair->stun_client->peer_addr;
        request_dst=&pair->remote->addr;
        if (nr_transport_addr_cmp(response_src,request_dst,NR_TRANSPORT_ADDR_CMP_MODE_ALL)){
          r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s)/CAND-PAIR(%s): Peer address mismatch %s != %s",pair->pctx->label,pair->codeword,response_src->as_string,request_dst->as_string);
          nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FAILED);
          break;
        }
        request_src=&pair->stun_client->my_addr;
        nr_socket_getaddr(pair->local->osock,&response_dst);
        if (nr_transport_addr_cmp(request_src,&response_dst,NR_TRANSPORT_ADDR_CMP_MODE_ALL)){
          r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s)/CAND-PAIR(%s): Local address mismatch %s != %s",pair->pctx->label,pair->codeword,request_src->as_string,response_dst.as_string);
          nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FAILED);
          break;
        }

        if(strlen(pair->stun_client->results.ice_binding_response.mapped_addr.as_string)==0){
          /* we're using the mapped_addr returned by the server to lookup our
           * candidate, but if the server fails to do that we can't perform
           * the lookup -- this may be a BUG because if we've gotten here
           * then the transaction ID check succeeded, and perhaps we should
           * just assume that it's the server we're talking to and that our
           * peer is ok, but I'm not sure how that'll interact with the
           * peer reflexive logic below */
          r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s)/CAND-PAIR(%s): server failed to return mapped address on pair %s", pair->pctx->label,pair->codeword,pair->as_string);
          nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FAILED);
          break;
        }
        else if(!nr_transport_addr_cmp(&pair->local->addr,&pair->stun_client->results.ice_binding_response.mapped_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL)){
          nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_SUCCEEDED);
        }
        else{
          /* OK, this didn't correspond to a pair on the check list, but
             it probably matches one of our candidates */

          cand=TAILQ_FIRST(&pair->local->component->candidates);
          while(cand){
            if(!nr_transport_addr_cmp(&cand->addr,&pair->stun_client->results.ice_binding_response.mapped_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL))
              break;

            cand=TAILQ_NEXT(cand,entry_comp);
          }

          /* OK, nothing found, must be peer reflexive */
          if(!cand){
            if(r=nr_ice_candidate_create(pair->pctx->ctx,
              pair->local->component,pair->local->isock,pair->local->osock,
              PEER_REFLEXIVE,0,pair->local->component->component_id,&cand))
              ABORT(r);
            if(r=nr_transport_addr_copy(&cand->addr,&pair->stun_client->results.ice_binding_response.mapped_addr))
              ABORT(r);
            cand->state=NR_ICE_CAND_STATE_INITIALIZED;
            TAILQ_INSERT_TAIL(&pair->local->component->candidates,cand,entry_comp);
          }

          /* Note: we stomp the existing pair! */
          orig_pair=pair;
          if(r=nr_ice_candidate_pair_create(pair->pctx,cand,pair->remote,
            &pair))
            ABORT(r);

          nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_SUCCEEDED);

          if(r=nr_ice_component_insert_pair(pair->remote->component,pair))
            ABORT(r);

          /* If the original pair was nominated, make us nominated,
             since we replace him*/
          if(orig_pair->peer_nominated)
            pair->peer_nominated=1;


          /* Now mark the orig pair failed */
          nr_ice_candidate_pair_set_state(orig_pair->pctx,orig_pair,NR_ICE_PAIR_STATE_FAILED);

        }

        /* Should we set nominated? */
        if(pair->pctx->controlling){
          if(pair->pctx->ctx->flags & NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION)
            pair->nominated=1;
        }
        else{
          if(pair->peer_nominated)
            pair->nominated=1;
        }


        /* increment the number of valid pairs in the component */
        /* We don't bother to maintain a separate valid list */
        pair->remote->component->valid_pairs++;

        /* S 7.1.2.2: unfreeze other pairs with the same foundation*/
        if(r=nr_ice_media_stream_unfreeze_pairs_foundation(pair->remote->stream,pair->foundation))
          ABORT(r);

        /* Deal with this pair being nominated */
        if(pair->nominated){
          if(r=nr_ice_component_nominated_pair(pair->remote->component, pair))
            ABORT(r);
        }

        break;
      default:
        ABORT(R_INTERNAL);
    }

    /* If we're controlling but in regular mode, ask the handler
       if he wants to nominate something and stop... */
    if(pair->pctx->controlling && !(pair->pctx->ctx->flags & NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION)){

      if(r=nr_ice_component_select_pair(pair->pctx,pair->remote->component)){
        if(r!=R_NOT_FOUND)
          ABORT(r);
      }
    }

  done:
    _status=0;
  abort:
    return;
  }
示例#22
0
int nr_stun_client_process_response(nr_stun_client_ctx *ctx, UCHAR *msg, int len, nr_transport_addr *peer_addr)
{
    int r,_status;
    char string[256];
    Data *password = 0;
    nr_stun_message_attribute *attr;
    nr_transport_addr *mapped_addr = 0;

    if(ctx->state==NR_STUN_CLIENT_STATE_CANCELLED)
        ABORT(R_REJECTED);

    if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING)
        ABORT(R_REJECTED);

    r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Received(my_addr=%s,peer_addr=%s)",ctx->label,ctx->my_addr.as_string,peer_addr->as_string);

    snprintf(string, sizeof(string)-1, "STUN-CLIENT(%s): Received ", ctx->label);
    r_dump(NR_LOG_STUN, LOG_DEBUG, string, (char*)msg, len);

    /* determine password */
    switch (ctx->mode) {
    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_LONG_TERM_AUTH:
    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH:
        password = ctx->params.stun_binding_request.password;
        break;

    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH:
        /* do nothing */
        break;

    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96:
        /* do nothing */
        break;

#ifdef USE_ICE
    case NR_ICE_CLIENT_MODE_BINDING_REQUEST:
        password = &ctx->params.ice_binding_request.password;
        break;
    case NR_ICE_CLIENT_MODE_USE_CANDIDATE:
        password = &ctx->params.ice_binding_request.password;
        break;
#endif /* USE_ICE */

#ifdef USE_TURN
    case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST1:
        /* do nothing */
        break;
    case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST2:
        /* do nothing */
        break;
    case NR_TURN_CLIENT_MODE_SET_ACTIVE_DEST_REQUEST:
        /* do nothing */
        break;
    case NR_TURN_CLIENT_MODE_SEND_INDICATION:
        /* do nothing -- we just got our DATA-INDICATION */
        break;
#endif /* USE_TURN */

    default:
        assert(0);
        ABORT(R_FAILED);
        break;
    }

#ifdef USE_TURN
    if (ctx->mode == NR_TURN_CLIENT_MODE_SEND_INDICATION) {
        /* SEND-INDICATION gets a DATA-INDICATION back, which will always
         * be a different transaction, so don't perform the check in that
         * case */
    }
#endif /* USE_TURN */

    if ((r=nr_stun_message_create2(&ctx->response, msg, len)))
        ABORT(r);

    if ((r=nr_stun_decode_message(ctx->response, nr_stun_client_get_password, password)))
        ABORT(r);

    if ((r=nr_stun_receive_message(ctx->request, ctx->response)))
        ABORT(r);

    /* TODO: !nn! currently using password!=0 to mean that auth is required,
     * TODO: !nn! but we should probably pass that in explicitly via the
     * TODO: !nn! usage (ctx->mode?) */
    if (password) {
        if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_NONCE, 0)) {
            if ((r=nr_stun_receive_response_long_term_auth(ctx->response, ctx)))
                ABORT(r);
        }
        else {
            if ((r=nr_stun_receive_response_short_term_auth(ctx->response)))
                ABORT(r);
        }
    }

    if (NR_STUN_GET_TYPE_CLASS(ctx->response->header.type) == NR_CLASS_RESPONSE) {
        if ((r=nr_stun_process_success_response(ctx->response)))
            ABORT(r);
    }
    else {
        if ((r=nr_stun_process_error_response(ctx->response))) {
            ABORT(r);
        }
        else {
            /* drop the error on the floor */
            ABORT(R_FAILED);
        }
    }

    /* TODO: !nn! this should be moved to individual message receive/processing sections */
    switch (ctx->mode) {
    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_LONG_TERM_AUTH:
    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);

        mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
        break;

    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);

        mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
        break;

    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MAPPED_ADDRESS, 0) && ! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);

        mapped_addr = &ctx->results.stun_binding_response_stund_0_96.mapped_addr;
        break;

#ifdef USE_ICE
    case NR_ICE_CLIENT_MODE_BINDING_REQUEST:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);

        mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
        break;
    case NR_ICE_CLIENT_MODE_USE_CANDIDATE:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);

        mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
        break;
#endif /* USE_ICE */

#ifdef USE_TURN
    case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST1:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_REALM, &attr))
            ABORT(R_BAD_DATA);

        ctx->results.allocate_response1.realm = attr->u.realm;

        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_NONCE, &attr))
            ABORT(R_BAD_DATA);

        ctx->results.allocate_response1.nonce = attr->u.nonce;
        break;
    case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST2:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_USERNAME, 0))
            ABORT(R_BAD_DATA);
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);

        if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_RELAY_ADDRESS, &attr)) {
            if ((r=nr_transport_addr_copy(
                        &ctx->results.allocate_response2.relay_addr,
                        &attr->u.relay_address)))
                ABORT(r);
        }
        else {
            if ((r=nr_transport_addr_copy(&ctx->results.allocate_response2.relay_addr, peer_addr)))
                ABORT(r);
        }

        mapped_addr = &ctx->results.allocate_response2.mapped_addr;

        break;
    case NR_TURN_CLIENT_MODE_SET_ACTIVE_DEST_REQUEST:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);
        break;
    case NR_TURN_CLIENT_MODE_SEND_INDICATION:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_REMOTE_ADDRESS, 0))
            ABORT(R_BAD_DATA);
        break;
#endif /* USE_TURN */

    default:
        assert(0);
        ABORT(R_FAILED);
        break;
    }

    /* make sure we have the most up-to-date address from this peer */
    if (nr_transport_addr_cmp(&ctx->peer_addr, peer_addr, NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
        r_log(NR_LOG_STUN,LOG_INFO,"STUN-CLIENT(%s): Peer moved from %s to %s", ctx->label, ctx->peer_addr.as_string, peer_addr->as_string);
        nr_transport_addr_copy(&ctx->peer_addr, peer_addr);
    }

    if (mapped_addr) {
        if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, &attr)) {
            if ((r=nr_transport_addr_copy(mapped_addr, &attr->u.xor_mapped_address.unmasked)))
                ABORT(r);
        }
        else if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MAPPED_ADDRESS, &attr)) {
            if ((r=nr_transport_addr_copy(mapped_addr, &attr->u.mapped_address)))
                ABORT(r);
        }
        else
            ABORT(R_BAD_DATA);

        r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Received mapped address: %s", ctx->label, mapped_addr->as_string);
    }

    ctx->state=NR_STUN_CLIENT_STATE_DONE;

    _status=0;
abort:
    if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING) {
        /* Cancel the timer firing */
        if (ctx->timer_handle) {
            NR_async_timer_cancel(ctx->timer_handle);
            ctx->timer_handle = 0;
        }

        /* Fire the callback */
        if (ctx->finished_cb) {
            NR_async_cb finished_cb = ctx->finished_cb;
            ctx->finished_cb = 0;  /* prevent 2nd call */
            /* finished_cb call must be absolutely last thing in function
             * because as a side effect this ctx may be operated on in the
             * callback */
            finished_cb(0,0,ctx->cb_arg);
        }
    }

    return(_status);
}
示例#23
0
int NrSocket::getaddr(nr_transport_addr *addrp) {
  ASSERT_ON_THREAD(ststhread_);
  return nr_transport_addr_copy(addrp, &my_addr_);
}
示例#24
0
int nr_turn_client_parse_data_indication(nr_turn_client_ctx *ctx,
                                         nr_transport_addr *source_addr,
                                         UCHAR *msg, size_t len,
                                         UCHAR *newmsg, size_t *newlen,
                                         size_t newsize,
                                         nr_transport_addr *remote_addr)
{
  int r,_status;
  nr_stun_message *ind=0;
  nr_stun_message_attribute *attr;
  nr_turn_permission *perm;

  if (nr_transport_addr_cmp(&ctx->turn_server_addr, source_addr,
                            NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
    r_log(NR_LOG_TURN, LOG_WARNING,
          "TURN(%s): Indication from unexpected source addr %s (expected %s)",
          ctx->label, source_addr->as_string, ctx->turn_server_addr.as_string);
    ABORT(R_REJECTED);
  }

  if ((r=nr_stun_message_create2(&ind, msg, len)))
    ABORT(r);
  if ((r=nr_stun_decode_message(ind, 0, 0)))
    ABORT(r);

  if (ind->header.type != NR_STUN_MSG_DATA_INDICATION)
    ABORT(R_BAD_ARGS);

  if (!nr_stun_message_has_attribute(ind, NR_STUN_ATTR_XOR_PEER_ADDRESS, &attr))
    ABORT(R_BAD_ARGS);

  if ((r=nr_turn_permission_find(ctx, &attr->u.xor_mapped_address.unmasked,
                                 &perm))) {
    if (r == R_NOT_FOUND) {
      r_log(NR_LOG_TURN, LOG_WARNING,
            "TURN(%s): Indication from peer addr %s with no permission",
            ctx->label, attr->u.xor_mapped_address.unmasked.as_string);
    }
    ABORT(r);
  }

  if ((r=nr_transport_addr_copy(remote_addr,
                                &attr->u.xor_mapped_address.unmasked)))
    ABORT(r);

#if REFRESH_RESERVATION_ON_RECV
  if ((r=nr_turn_client_ensure_perm(ctx, remote_addr))) {
    ABORT(r);
  }
#endif

  if (!nr_stun_message_has_attribute(ind, NR_STUN_ATTR_DATA, &attr)) {
    ABORT(R_BAD_DATA);
  }

  assert(newsize >= attr->u.data.length);
  if (newsize < attr->u.data.length)
    ABORT(R_BAD_ARGS);

  memcpy(newmsg, attr->u.data.data, attr->u.data.length);
  *newlen = attr->u.data.length;

  _status=0;
abort:
  nr_stun_message_destroy(&ind);
  return(_status);
}
示例#25
0
// nr_socket APIs (as member functions)
int NrSocket::create(nr_transport_addr *addr) {
  int r,_status;

  PRStatus status;
  PRNetAddr naddr;

  nsresult rv;
  nsCOMPtr<nsISocketTransportService> stservice =
      do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);

  if (!NS_SUCCEEDED(rv)) {
    ABORT(R_INTERNAL);
  }

  if((r=nr_transport_addr_to_praddr(addr, &naddr)))
    ABORT(r);

  switch (addr->protocol) {
    case IPPROTO_UDP:
      if (!(fd_ = PR_NewUDPSocket())) {
        r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create socket");
        ABORT(R_INTERNAL);
      }
      break;
    case IPPROTO_TCP:
      if (!(fd_ = PR_NewTCPSocket())) {
        r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create socket");
        ABORT(R_INTERNAL);
      }
      break;
    default:
      ABORT(R_INTERNAL);
  }

  status = PR_Bind(fd_, &naddr);
  if (status != PR_SUCCESS) {
    r_log(LOG_GENERIC,LOG_CRIT,"Couldn't bind socket to address %s",
          addr->as_string);
    ABORT(R_INTERNAL);
  }

  r_log(LOG_GENERIC,LOG_DEBUG,"Creating socket %p with addr %s",
        fd_, addr->as_string);
  nr_transport_addr_copy(&my_addr_,addr);

  /* If we have a wildcard port, patch up the addr */
  if(nr_transport_addr_is_wildcard(addr)){
    status = PR_GetSockName(fd_, &naddr);
    if (status != PR_SUCCESS){
      r_log(LOG_GENERIC, LOG_CRIT, "Couldn't get sock name for socket");
      ABORT(R_INTERNAL);
    }

    if((r=nr_praddr_to_transport_addr(&naddr,&my_addr_,addr->protocol,1)))
      ABORT(r);
  }


  // Set nonblocking
  PRSocketOptionData option;
  option.option = PR_SockOpt_Nonblocking;
  option.value.non_blocking = PR_TRUE;
  status = PR_SetSocketOption(fd_, &option);
  if (status != PR_SUCCESS) {
    r_log(LOG_GENERIC, LOG_CRIT, "Couldn't make socket nonblocking");
    ABORT(R_INTERNAL);
  }

  // Remember our thread.
  ststhread_ = do_QueryInterface(stservice, &rv);
  if (!NS_SUCCEEDED(rv))
    ABORT(R_INTERNAL);

  // Finally, register with the STS
  rv = stservice->AttachSocket(fd_, this);
  if (!NS_SUCCEEDED(rv)) {
    ABORT(R_INTERNAL);
  }

  _status = 0;

abort:
  return(_status);
}
int NrSocket::getaddr(nr_transport_addr *addrp) {
  return nr_transport_addr_copy(addrp, &my_addr_);
}
示例#27
0
static void s_cb(int s, int how, void *cb_arg)
  {
#if 0
    nr_socket *sock = (nr_socket*)cb_arg;
    UCHAR buf2[4096];
    size_t len;
    nr_transport_addr addr2;
    int r;
    StunMessage req;
    StunMessage res;
    //StunAddress4 from;

    fprintf(stderr,"TURN_SERVER_UTIL: SERVER CB\n");

    if(r=nr_socket_recvfrom(sock,buf2,sizeof(buf2),&len,0,&addr2)){
      fprintf(stderr,"Error in recvfrom\n");
      exit(1);
    }

    memset(&req, 0, sizeof(req));
    memset(&res, 0, sizeof(res));
    //memset(&from, 0, sizeof(from));
    //from.addr = ntohl(addr2.u.addr4.sin_addr.s_addr);
    //from.port = ntohs(addr2.u.addr4.sin_port);

    if ((r=nr_stun_parse_message((char*)buf2, len, &req))) {
      fprintf(stderr,"Error in nr_stun_parse_message\n");
      exit(1);
    }

    if ((r=nr_stun_process_request(&req, buf2, len, &addr2, 0, 0, &res))) {
        /* failure is expected because the server code doesn't support TURN */
        if (r!=R_FAILED) {
            fprintf(stderr,"Failed to process message!\n");
            exit(1);
        }
        fprintf(stderr,"TURN_SERVER_UTIL: No problem with parse failure ... process TURN in test server code\n");
    }

    if (!nr_is_stun_message((char*)buf2, len)) {
        fprintf(stderr,"TURN_SERVER_UTIL: not a STUN/TURN message\n");
        /* instead of sending to remoteAddress, just echo the content back
         * for the purposes of our tests */
        goto send;
    }

    res.hasFingerprint = 1;

    switch (req.msgHdr.msgType) {
    case AllocateRequestMsg:
       if (! req.hasNonce) {
           fprintf(stderr, "Received AllocateRequestMsg #1\n");
           assert(!req.hasMessageIntegrity);
/* TODO: what about username: does it go into the req or not? spec not clear */
           res.msgHdr.msgType = AllocateErrorResponseMsg;
           res.hasUsername = 0;
           res.hasNonce = 1;
           strcpy(res.nonce, nonce);
           res.hasRealm = 1;
           strcpy(res.realm, "REALM");
           res.hasErrorCode = 1;
           res.errorCode.errorClass = 4;
           res.errorCode.number = 35;
       }
       else {
           fprintf(stderr, "Received AllocateRequestMsg #2\n");
           assert(req.hasUsername);
           assert(req.hasRealm);
           assert(req.hasNonce);
           assert(req.hasMessageIntegrity);
           res.msgHdr.msgType = AllocateResponseMsg;
           res.hasUsername = 1;
           res.hasMessageIntegrity = 1;
           strcpy(res.username, req.username);
#if 0
//TODO: this is totally broken, but TURN is changing and so
//TODO: we'll need to take another pass at all this code
//TODO: anyhow, so leave it broken for now
           res.hasRelayAddress = 1;
           res.relayAddress.family = IPv4Family;
           res.relayAddress.ipv4.addr = from.addr;
           res.relayAddress.ipv4.port = from.port;
           res.hasXorMappedAddress = 1;
           res.xorMappedAddress.family = IPv4Family;
           res.xorMappedAddress.ipv4.addr = from.addr;
           res.xorMappedAddress.ipv4.port = from.port;
#endif
       }
       break;
    case SendIndicationMsg:
       fprintf(stderr, "Received SendIndicationMsg\n");
       assert(req.hasRemoteAddress);

       /* pretend to send empty UDP packet to remoteAddress per the
        * TURN spec and to wait for a DataIndication resonse */
       fprintf(stderr, "Sending UDP packet to REMOTE-ADDRESS...\n");
       fprintf(stderr, "Waiting for response from REMOTE-ADDRESS...\n");

       /* ok, this is an indication, so formally there is no "response",
        * but we're going to send a data indication to it, so just pretend
        * that it's a formal response */
       res.msgHdr.msgType = DataIndicationMsg;
       res.hasRemoteAddress = 1;
       nr_transport_addr_copy(&res.remoteAddress, &req.remoteAddress);

       break;
    case SetActiveDestRequestMsg:
       fprintf(stderr, "Received SetActiveDestRequestMsg\n");
       assert(req.hasRemoteAddress);
 
       res.msgHdr.msgType = SetActiveDestResponseMsg;
       break;
    default:
       assert(0);
       break;
    }

   memset(&buf2, 0, sizeof(buf2));

   if ((r=nr_stun_encode_message(STUN_MODE_STUN, &res, (char*)buf2, STUN_MAX_MESSAGE_SIZE, &pass, (unsigned int*)&len))) {
      fprintf(stderr,"Error encoding TURN response\n");
      exit(1);
    }

 send:
   fprintf(stderr,"Sending response to %s\n", addr2.as_string);
   if(r=nr_socket_sendto(sock,buf2,len,0,&addr2)) {
      fprintf(stderr,"Error sending TURN response\n");
      exit(1);
    }

    NR_ASYNC_WAIT(s, how, s_cb, cb_arg);
#else
UNIMPLEMENTED;
#endif
  }
示例#28
0
int nr_stun_client_process_response(nr_stun_client_ctx *ctx, UCHAR *msg, int len, nr_transport_addr *peer_addr)
  {
    int r,_status;
    char string[256];
    char *username = 0;
    Data *password = 0;
    nr_stun_message_attribute *attr;
    nr_transport_addr *mapped_addr = 0;
    int fail_on_error = 0;
    UCHAR hmac_key_d[16];
    Data hmac_key;
    int compute_lt_key=0;
    /* TODO([email protected]): Bug 1023619, refactor this. */
    int response_matched=0;

    ATTACH_DATA(hmac_key, hmac_key_d);

    if ((ctx->state != NR_STUN_CLIENT_STATE_RUNNING) &&
        (ctx->state != NR_STUN_CLIENT_STATE_WAITING))
      ABORT(R_REJECTED);

    r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Inspecting STUN response (my_addr=%s, peer_addr=%s)",ctx->label,ctx->my_addr.as_string,peer_addr->as_string);

    snprintf(string, sizeof(string)-1, "STUN-CLIENT(%s): Received ", ctx->label);
    r_dump(NR_LOG_STUN, LOG_DEBUG, string, (char*)msg, len);

    /* determine password */
    switch (ctx->mode) {
    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_LONG_TERM_AUTH:
      compute_lt_key = 1;
      /* Fall through */
    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH:
        password = ctx->params.stun_binding_request.password;
        break;

    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH:
        /* do nothing */
        break;

    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96:
        /* do nothing */
        break;

#ifdef USE_ICE
    case NR_ICE_CLIENT_MODE_BINDING_REQUEST:
        password = &ctx->params.ice_binding_request.password;
        break;
    case NR_ICE_CLIENT_MODE_USE_CANDIDATE:
        password = &ctx->params.ice_binding_request.password;
        break;
#endif /* USE_ICE */

#ifdef USE_TURN
    case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST:
      fail_on_error = 1;
      compute_lt_key = 1;
        username = ctx->auth_params.username;
        password = &ctx->auth_params.password;
        /* do nothing */
        break;
    case NR_TURN_CLIENT_MODE_REFRESH_REQUEST:
      fail_on_error = 1;
      compute_lt_key = 1;
        username = ctx->auth_params.username;
        password = &ctx->auth_params.password;
        /* do nothing */
        break;
    case NR_TURN_CLIENT_MODE_PERMISSION_REQUEST:
      fail_on_error = 1;
      compute_lt_key = 1;
        username = ctx->auth_params.username;
        password = &ctx->auth_params.password;
        /* do nothing */
        break;
    case NR_TURN_CLIENT_MODE_SEND_INDICATION:
        /* do nothing -- we just got our DATA-INDICATION */
        break;
#endif /* USE_TURN */

    default:
        assert(0);
        ABORT(R_FAILED);
        break;
    }

    if (compute_lt_key) {
      if (!ctx->realm || !username) {
        r_log(NR_LOG_STUN, LOG_DEBUG, "Long-term auth required but no realm/username specified. Randomizing key");
        /* Fill the key with random bytes to guarantee non-match */
        if (r=nr_crypto_random_bytes(hmac_key_d, sizeof(hmac_key_d)))
          ABORT(r);
      }
      else {
        if (r=nr_stun_compute_lt_message_integrity_password(username, ctx->realm,
                                                            password, &hmac_key))
          ABORT(r);
      }
      password = &hmac_key;
    }

    if (ctx->response) {
      nr_stun_message_destroy(&ctx->response);
    }

    /* TODO([email protected]): Bug 1023619, refactor this. */
    if ((r=nr_stun_message_create2(&ctx->response, msg, len)))
        ABORT(r);

    if ((r=nr_stun_decode_message(ctx->response, nr_stun_client_get_password, password))) {
        r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): error decoding response",ctx->label);
        ABORT(r);
    }

    /* This will return an error if request and response don't match,
       which is how we reject responses that match other contexts. */
    if ((r=nr_stun_receive_message(ctx->request, ctx->response))) {
        r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Response is not for us",ctx->label);
        ABORT(r);
    }

    r_log(NR_LOG_STUN,LOG_INFO,
          "STUN-CLIENT(%s): Received response; processing",ctx->label);
    response_matched=1;

/* TODO: !nn! currently using password!=0 to mean that auth is required,
 * TODO: !nn! but we should probably pass that in explicitly via the
 * TODO: !nn! usage (ctx->mode?) */
    if (password) {
        if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_NONCE, 0)) {
            if ((r=nr_stun_receive_response_long_term_auth(ctx->response, ctx)))
                ABORT(r);
        }
        else {
            if ((r=nr_stun_receive_response_short_term_auth(ctx->response)))
                ABORT(r);
        }
    }

    if (NR_STUN_GET_TYPE_CLASS(ctx->response->header.type) == NR_CLASS_RESPONSE) {
        if ((r=nr_stun_process_success_response(ctx->response)))
            ABORT(r);
    }
    else {
      if (fail_on_error) {
        ctx->state = NR_STUN_CLIENT_STATE_FAILED;
      }
        /* Note: most times we call process_error_response, we get r != 0.

           However, if the error is to be discarded, we get r == 0, smash
           the error code, and just keep going.
        */
        if ((r=nr_stun_process_error_response(ctx->response, &ctx->error_code))) {
            ABORT(r);
        }
        else {
          ctx->error_code = 0xffff;
            /* drop the error on the floor */
            ABORT(R_FAILED);
        }
    }

    r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Successfully parsed mode=%d",ctx->label,ctx->mode);

/* TODO: !nn! this should be moved to individual message receive/processing sections */
    switch (ctx->mode) {
    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_LONG_TERM_AUTH:
    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);

        mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
        break;

    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0)) {
            if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MAPPED_ADDRESS, 0)) {
              /* Compensate for a bug in Google's STUN servers where they always respond with MAPPED-ADDRESS */
              r_log(NR_LOG_STUN,LOG_INFO,"STUN-CLIENT(%s): No XOR-MAPPED-ADDRESS but MAPPED-ADDRESS. Falling back (though server is wrong).", ctx->label);
            }
            else {
              ABORT(R_BAD_DATA);
            }
        }

        mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
        break;

    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MAPPED_ADDRESS, 0) && ! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);

        mapped_addr = &ctx->results.stun_binding_response_stund_0_96.mapped_addr;
        break;

#ifdef USE_ICE
    case NR_ICE_CLIENT_MODE_BINDING_REQUEST:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);

        mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
        break;
    case NR_ICE_CLIENT_MODE_USE_CANDIDATE:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);

        mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
        break;
#endif /* USE_ICE */

#ifdef USE_TURN
    case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);

        if (!nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_RELAY_ADDRESS, &attr))
          ABORT(R_BAD_DATA);

        if ((r=nr_stun_transport_addr_check(&attr->u.relay_address.unmasked,
                                            ctx->mapped_addr_check_mask)))
          ABORT(r);

        if ((r=nr_transport_addr_copy(
                &ctx->results.allocate_response.relay_addr,
                &attr->u.relay_address.unmasked)))
          ABORT(r);

        if (!nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_LIFETIME, &attr))
          ABORT(R_BAD_DATA);
        ctx->results.allocate_response.lifetime_secs=attr->u.lifetime_secs;

        r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Received relay address: %s", ctx->label, ctx->results.allocate_response.relay_addr.as_string);

        mapped_addr = &ctx->results.allocate_response.mapped_addr;

        break;
    case NR_TURN_CLIENT_MODE_REFRESH_REQUEST:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);
        if (!nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_LIFETIME, &attr))
          ABORT(R_BAD_DATA);
        ctx->results.refresh_response.lifetime_secs=attr->u.lifetime_secs;
        break;
    case NR_TURN_CLIENT_MODE_PERMISSION_REQUEST:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);
        break;
#endif /* USE_TURN */

    default:
        assert(0);
        ABORT(R_FAILED);
        break;
    }

    /* make sure we have the most up-to-date address from this peer */
    if (nr_transport_addr_cmp(&ctx->peer_addr, peer_addr, NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
        r_log(NR_LOG_STUN,LOG_INFO,"STUN-CLIENT(%s): Peer moved from %s to %s", ctx->label, ctx->peer_addr.as_string, peer_addr->as_string);
        nr_transport_addr_copy(&ctx->peer_addr, peer_addr);
    }

    if (mapped_addr) {
        if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, &attr)) {
            if ((r=nr_stun_transport_addr_check(&attr->u.xor_mapped_address.unmasked,
                                                ctx->mapped_addr_check_mask)))
                ABORT(r);

            if ((r=nr_transport_addr_copy(mapped_addr, &attr->u.xor_mapped_address.unmasked)))
                ABORT(r);
        }
        else if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MAPPED_ADDRESS, &attr)) {
            if ((r=nr_stun_transport_addr_check(&attr->u.mapped_address,
                                                ctx->mapped_addr_check_mask)))
                ABORT(r);

            if ((r=nr_transport_addr_copy(mapped_addr, &attr->u.mapped_address)))
                ABORT(r);
        }
        else
            ABORT(R_BAD_DATA);

        // STUN doesn't distinguish protocol in mapped address, therefore
        // assign used protocol from peer_addr
        if (mapped_addr->protocol!=peer_addr->protocol){
          mapped_addr->protocol=peer_addr->protocol;
          nr_transport_addr_fmt_addr_string(mapped_addr);
        }

        r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Received mapped address: %s", ctx->label, mapped_addr->as_string);
    }

    ctx->state=NR_STUN_CLIENT_STATE_DONE;

    _status=0;
  abort:
    if(_status && response_matched){
      r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): Error processing response: %s, stun error code %d.", ctx->label, nr_strerror(_status), (int)ctx->error_code);
    }

    if ((ctx->state != NR_STUN_CLIENT_STATE_RUNNING) &&
        (ctx->state != NR_STUN_CLIENT_STATE_WAITING)) {
        /* Cancel the timer firing */
        if (ctx->timer_handle) {
            NR_async_timer_cancel(ctx->timer_handle);
            ctx->timer_handle = 0;
        }

        nr_stun_client_fire_finished_cb(ctx);
    }

    return(_status);
  }
示例#29
0
int nr_stun_client_ctx_create(char *label, nr_socket *sock, nr_transport_addr *peer, UINT4 RTO, nr_stun_client_ctx **ctxp)
  {
    nr_stun_client_ctx *ctx=0;
    char allow_loopback;
    int r,_status;

    if ((r=nr_stun_startup()))
      ABORT(r);

    if(!(ctx=RCALLOC(sizeof(nr_stun_client_ctx))))
      ABORT(R_NO_MEMORY);

    ctx->state=NR_STUN_CLIENT_STATE_INITTED;

    if(!(ctx->label=r_strdup(label)))
      ABORT(R_NO_MEMORY);

    ctx->sock=sock;

    nr_socket_getaddr(sock,&ctx->my_addr);
    nr_transport_addr_copy(&ctx->peer_addr,peer);

    if (RTO != 0) {
      ctx->rto_ms = RTO;
    } else if (NR_reg_get_uint4(NR_STUN_REG_PREF_CLNT_RETRANSMIT_TIMEOUT, &ctx->rto_ms)) {
      ctx->rto_ms = 100;
    }

    if (NR_reg_get_double(NR_STUN_REG_PREF_CLNT_RETRANSMIT_BACKOFF, &ctx->retransmission_backoff_factor))
      ctx->retransmission_backoff_factor = 2.0;

    if (NR_reg_get_uint4(NR_STUN_REG_PREF_CLNT_MAXIMUM_TRANSMITS, &ctx->maximum_transmits))
      ctx->maximum_transmits = 7;

    if (NR_reg_get_uint4(NR_STUN_REG_PREF_CLNT_FINAL_RETRANSMIT_BACKOFF, &ctx->maximum_transmits_timeout_ms))
      ctx->maximum_transmits_timeout_ms = 16 * ctx->rto_ms;

    ctx->mapped_addr_check_mask = NR_STUN_TRANSPORT_ADDR_CHECK_WILDCARD;
    if (NR_reg_get_char(NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, &allow_loopback) ||
        !allow_loopback) {
      ctx->mapped_addr_check_mask |= NR_STUN_TRANSPORT_ADDR_CHECK_LOOPBACK;
    }

    if (ctx->my_addr.protocol == IPPROTO_TCP) {
      /* Because TCP is reliable there is only one final timeout value.
       * We store the timeout value for TCP in here, because timeout_ms gets
       * reset to 0 in client_reset() which gets called from client_start() */
      ctx->maximum_transmits_timeout_ms = ctx->rto_ms *
                        pow(ctx->retransmission_backoff_factor,
                            ctx->maximum_transmits);
      ctx->maximum_transmits = 1;
    }

    *ctxp=ctx;

    _status=0;
  abort:
    if(_status){
      nr_stun_client_ctx_destroy(&ctx);
    }
    return(_status);
  }