static void nr_stun_send_test( Socket myFd, StunAddress4* dest, StunAtrString* username, StunAtrString* password, int testNum) { int r,_status; nr_stun_message *msg; nr_stun_client_stun_binding_request_params params; Data password2; assert( dest->addr != 0 ); assert( dest->port != 0 ); params.username = username->value; password2.data = (UCHAR*)password->value; password2.len = password->sizeValue; params.password = &password2; switch (stun_mode) { default: switch (auth_rule) { case NR_STUN_AUTH_RULE_OPTIONAL: if ((r=nr_stun_build_req_no_auth(¶ms, &msg))) ABORT(r); break; case NR_STUN_AUTH_RULE_SHORT_TERM: if ((r=nr_stun_build_req_st_auth(¶ms, &msg))) ABORT(r); break; case NR_STUN_AUTH_RULE_LONG_TERM: if ((r=nr_stun_build_req_lt_auth(¶ms, &msg))) ABORT(r); break; } break; #ifdef USE_STUND_0_96 case NR_STUN_MODE_STUND_0_96: if ((r=nr_stun_build_req_stund_0_96(0, &msg))) ABORT(r); break; #endif /* USE_STUND_0_96 */ } if ((r=nr_stun_encode_message(msg))) ABORT(r); r_log(NR_LOG_STUN, LOG_DEBUG, "About to send msg of len %d to %s",msg->length,nr_ip4toa(dest)); sendMessage( myFd, (char*)msg->buffer, msg->length, dest->addr, dest->port); _status=0; abort: // return _status; return; }
/* 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_send_stun_request(nr_turn_client_ctx *ctx, nr_stun_message *req, int flags) { int r,_status; if ((r=nr_stun_encode_message(req))) ABORT(r); if ((r=nr_socket_sendto(ctx->sock, req->buffer, req->length, flags, &ctx->turn_server_addr))) { r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): Failed sending request", ctx->label); ABORT(r); } _status=0; abort: return(_status); }
static int nr_stun_client_send_request(nr_stun_client_ctx *ctx) { int r,_status; char string[256]; if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING) ABORT(R_NOT_PERMITTED); r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Sending check request (my_addr=%s,peer_addr=%s)",ctx->label,ctx->my_addr.as_string,ctx->peer_addr.as_string); if (ctx->request == 0) { switch (ctx->mode) { case NR_STUN_CLIENT_MODE_BINDING_REQUEST_LONG_TERM_AUTH: ctx->params.stun_binding_request.nonce = ctx->nonce; ctx->params.stun_binding_request.realm = ctx->realm; assert(0); ABORT(R_INTERNAL); /* TODO([email protected]): Need to implement long-term auth for binding requests */ if ((r=nr_stun_build_req_lt_auth(&ctx->params.stun_binding_request, &ctx->request))) ABORT(r); break; case NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH: if ((r=nr_stun_build_req_st_auth(&ctx->params.stun_binding_request, &ctx->request))) ABORT(r); break; case NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH: if ((r=nr_stun_build_req_no_auth(&ctx->params.stun_binding_request, &ctx->request))) ABORT(r); break; case NR_STUN_CLIENT_MODE_KEEPALIVE: if ((r=nr_stun_build_keepalive(&ctx->params.stun_keepalive, &ctx->request))) ABORT(r); break; #ifdef USE_STUND_0_96 case NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96: if ((r=nr_stun_build_req_stund_0_96(&ctx->params.stun_binding_request_stund_0_96, &ctx->request))) ABORT(r); break; #endif /* USE_STUND_0_96 */ #ifdef USE_ICE case NR_ICE_CLIENT_MODE_USE_CANDIDATE: if ((r=nr_stun_build_use_candidate(&ctx->params.ice_binding_request, &ctx->request))) ABORT(r); break; case NR_ICE_CLIENT_MODE_BINDING_REQUEST: if ((r=nr_stun_build_req_ice(&ctx->params.ice_binding_request, &ctx->request))) ABORT(r); break; #endif /* USE_ICE */ #ifdef USE_TURN case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST: if ((r=nr_stun_build_allocate_request(&ctx->auth_params, &ctx->params.allocate_request, &ctx->request))) ABORT(r); break; case NR_TURN_CLIENT_MODE_REFRESH_REQUEST: if ((r=nr_stun_build_refresh_request(&ctx->auth_params, &ctx->params.refresh_request, &ctx->request))) ABORT(r); break; case NR_TURN_CLIENT_MODE_PERMISSION_REQUEST: if ((r=nr_stun_build_permission_request(&ctx->auth_params, &ctx->params.permission_request, &ctx->request))) ABORT(r); break; case NR_TURN_CLIENT_MODE_SEND_INDICATION: if ((r=nr_stun_build_send_indication(&ctx->params.send_indication, &ctx->request))) ABORT(r); break; #endif /* USE_TURN */ default: assert(0); ABORT(R_FAILED); break; } } if (ctx->request->length == 0) { if ((r=nr_stun_encode_message(ctx->request))) ABORT(r); } snprintf(string, sizeof(string)-1, "STUN-CLIENT(%s): Sending to %s ", ctx->label, ctx->peer_addr.as_string); r_dump(NR_LOG_STUN, LOG_DEBUG, string, (char*)ctx->request->buffer, ctx->request->length); assert(ctx->my_addr.protocol==ctx->peer_addr.protocol); if(r=nr_socket_sendto(ctx->sock, ctx->request->buffer, ctx->request->length, 0, &ctx->peer_addr)) ABORT(r); ctx->request_ct++; if (NR_STUN_GET_TYPE_CLASS(ctx->request->header.type) == NR_CLASS_INDICATION) { /* no need to set the timer because indications don't receive a * response */ } else { if (ctx->request_ct >= ctx->maximum_transmits) { /* Reliable transport only get here once. Unreliable get here for * their final timeout. */ ctx->timeout_ms += ctx->maximum_transmits_timeout_ms; } else if (ctx->timeout_ms) { /* exponential backoff */ ctx->timeout_ms *= ctx->retransmission_backoff_factor; } else { /* initial timeout unreliable transports */ ctx->timeout_ms = ctx->rto_ms; } r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Next timer will fire in %u ms",ctx->label, ctx->timeout_ms); gettimeofday(&ctx->timer_set, 0); assert(ctx->timeout_ms); NR_ASYNC_TIMER_SET(ctx->timeout_ms, nr_stun_client_timer_expired_cb, ctx, &ctx->timer_handle); } _status=0; abort: if (_status) { nr_stun_client_failed(ctx); } return(_status); }
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 }
static int nr_stun_client_send_request(nr_stun_client_ctx *ctx) { int r,_status; char string[256]; if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING) ABORT(R_NOT_PERMITTED); r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Sending(my_addr=%s,peer_addr=%s)",ctx->label,ctx->my_addr.as_string,ctx->peer_addr.as_string); if (ctx->request == 0) { switch (ctx->mode) { case NR_STUN_CLIENT_MODE_BINDING_REQUEST_LONG_TERM_AUTH: ctx->params.stun_binding_request.nonce = ctx->nonce; ctx->params.stun_binding_request.realm = ctx->realm; if ((r=nr_stun_build_req_lt_auth(&ctx->params.stun_binding_request, &ctx->request))) ABORT(r); break; case NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH: if ((r=nr_stun_build_req_st_auth(&ctx->params.stun_binding_request, &ctx->request))) ABORT(r); break; case NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH: if ((r=nr_stun_build_req_no_auth(&ctx->params.stun_binding_request, &ctx->request))) ABORT(r); break; case NR_STUN_CLIENT_MODE_KEEPALIVE: if ((r=nr_stun_build_keepalive(&ctx->params.stun_keepalive, &ctx->request))) ABORT(r); break; #ifdef USE_STUND_0_96 case NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96: if ((r=nr_stun_build_req_stund_0_96(&ctx->params.stun_binding_request_stund_0_96, &ctx->request))) ABORT(r); break; #endif /* USE_STUND_0_96 */ #ifdef USE_ICE case NR_ICE_CLIENT_MODE_USE_CANDIDATE: if ((r=nr_stun_build_use_candidate(&ctx->params.ice_use_candidate, &ctx->request))) ABORT(r); break; case NR_ICE_CLIENT_MODE_BINDING_REQUEST: if ((r=nr_stun_build_req_ice(&ctx->params.ice_binding_request, &ctx->request))) ABORT(r); break; #endif /* USE_ICE */ #ifdef USE_TURN case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST1: if ((r=nr_stun_build_allocate_request1(&ctx->params.allocate_request1, &ctx->request))) ABORT(r); break; case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST2: if ((r=nr_stun_build_allocate_request2(&ctx->params.allocate_request2, &ctx->request))) ABORT(r); break; case NR_TURN_CLIENT_MODE_SEND_INDICATION: if ((r=nr_stun_build_send_indication(&ctx->params.send_indication, &ctx->request))) ABORT(r); break; case NR_TURN_CLIENT_MODE_SET_ACTIVE_DEST_REQUEST: if ((r=nr_stun_build_set_active_dest_request(&ctx->params.set_active_dest_request, &ctx->request))) ABORT(r); break; case NR_TURN_CLIENT_MODE_DATA_INDICATION: if ((r=nr_stun_build_data_indication(&ctx->params.data_indication, &ctx->request))) ABORT(r); break; #endif /* USE_TURN */ default: assert(0); ABORT(R_FAILED); break; } } if (ctx->request->length == 0) { if ((r=nr_stun_encode_message(ctx->request))) ABORT(r); } snprintf(string, sizeof(string)-1, "STUN-CLIENT(%s): Sending to %s ", ctx->label, ctx->peer_addr.as_string); r_dump(NR_LOG_STUN, LOG_DEBUG, string, (char*)ctx->request->buffer, ctx->request->length); if(r=nr_socket_sendto(ctx->sock, ctx->request->buffer, ctx->request->length, 0, &ctx->peer_addr)) ABORT(r); ctx->request_ct++; if (NR_STUN_GET_TYPE_CLASS(ctx->request->header.type) == NR_CLASS_INDICATION) { /* no need to set the timer because indications don't receive a * response */ } else { if (ctx->request_ct < ctx->maximum_transmits) { ctx->timeout_ms *= ctx->retransmission_backoff_factor; ctx->timeout_ms += ctx->rto_ms; } else { ctx->timeout_ms += ctx->final_retransmit_backoff_ms; } r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Next timer will fire in %u ms",ctx->label, ctx->timeout_ms); gettimeofday(&ctx->timer_set, 0); NR_ASYNC_TIMER_SET(ctx->timeout_ms, nr_stun_client_timer_expired_cb, ctx, &ctx->timer_handle); } _status=0; abort: if (_status) { ctx->state=NR_STUN_CLIENT_STATE_FAILED; } return(_status); }
int nr_stun_server_process(StunServerInfo* info) { int r,_status; char msg[NR_STUN_MAX_MESSAGE_SIZE]; int msgLen = sizeof(msg); char ok = 0; char recvAltIp =0; char recvAltPort = 0; fd_set fdSet; Socket maxFd=0; struct timeval tv; nr_stun_message *req; nr_stun_message *resp; Data password = { (UCHAR*)"hello", 5 }; nr_transport_addr from2; FD_ZERO(&fdSet); FD_SET(info->myFd,&fdSet); if ( info->myFd >= maxFd ) maxFd=info->myFd+1; tv.tv_sec = 1; tv.tv_usec = 0; int e = select( maxFd, &fdSet, NULL,NULL, &tv ); if (e < 0) { r_log_e(NR_LOG_STUN, LOG_WARNING, "Error on select"); } else if (e >= 0) { StunAddress4 from; if (FD_ISSET(info->myFd,&fdSet)) { r_log(NR_LOG_STUN, LOG_DEBUG, "received on A1:P1"); recvAltIp = 0; recvAltPort = 0; ok = 1; if (getMessage( info->myFd, msg, &msgLen, &from.addr, &from.port)) ok = 0; } else { goto done; } if ( !ok ) { r_log(NR_LOG_STUN, LOG_DEBUG, "Get message did not return a valid message"); goto done; } r_log(NR_LOG_STUN, LOG_DEBUG, "Got request (len=%u) from %s",msgLen,nr_ip4toa(&from)); if ( msgLen <= 0 ) { goto done; } if ((r=nr_stun_message_create2(&req, (UCHAR*)msg, msgLen))) { fprintf(stderr,"Error in nr_stun_message_create2\n"); exit(1); } if ((r=nr_stun_decode_message(req, returnpassword, &password))) { fprintf(stderr,"Error in nr_stun_parse_message\n"); exit(1); } if ((r=nr_stun_message_create(&resp))) { fprintf(stderr,"Error in nr_stun_message_create\n"); exit(1); } nr_ip4_port_to_transport_addr(from.addr, from.port, IPPROTO_UDP, &from2); if ((r=nr_stun_receive_message(0, req))) { r_log(NR_LOG_STUN, LOG_DEBUG, "Failed to receive message"); nr_stun_form_error_response(req, resp, 400, "Bad Message"); } else if (alternate_server && from.addr != info->myAddr.addr) { /* NOTE: this code is broken because we don't want 'from', we want 'to', * but UNIX doesn't provide a way to easily get that information, so * the -a flag only works when the client and server reside on the * same machine */ /* send ALTERNATE-SERVER */ nr_transport_addr alternate_server; nr_stun_form_error_response(req, resp, 300, "Alternate Server"); nr_ip4_port_to_transport_addr(info->myAddr.addr, info->myAddr.port, IPPROTO_UDP, &alternate_server); nr_stun_message_add_alternate_server_attribute(resp, &alternate_server); } else if ((r=nr_stun_process_request(req,resp))) { r_log(NR_LOG_STUN, LOG_DEBUG, "Failed to process request"); /* continue, even though failed to parse message, to send error message */ } else { nr_stun_form_success_response(req, &from2, &password, resp); } if ((r=nr_stun_encode_message(resp))) { /* ignore this failure */ } else if (from.addr != 0 && from.port != 0) { if ( info->myFd != INVALID_SOCKET ) { sendMessage(info->myFd, (char*)resp->buffer, resp->length, from.addr, from.port); } } } done: _status=0; // abort: return _status; }