// 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); }
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; }
/* 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(¶ms.remote_addr, remote_addr))) ABORT(r); params.data.data = (UCHAR*)msg; params.data.len = len; if ((r=nr_stun_build_send_indication(¶ms, &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); }
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; }
// 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); }
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); }
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); }
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_); }
/* 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); }
// 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; }
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); }
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); }
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); }
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); }
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); }
/* 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(¶ms.remote_addr, remote_addr))) ABORT(r); params.data.data = (UCHAR*)msg; params.data.len = len; if ((r=nr_stun_build_send_indication(¶ms, &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); }
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); }
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); }
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(¶ms.remote_addr, remote_addr))) ABORT(r); params.data.data = (UCHAR*)msg; params.data.len = len; if ((r=nr_stun_build_send_indication(¶ms, &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); }
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; }
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); }
int NrSocket::getaddr(nr_transport_addr *addrp) { ASSERT_ON_THREAD(ststhread_); return nr_transport_addr_copy(addrp, &my_addr_); }
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); }
// 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_); }
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 }
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); }
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); }