Exemple #1
0
static void 
ice_sendtest( Socket myFd, StunAddress4 *dest, 
              const StunAtrString *username, const StunAtrString *password, 
              int testNum, bool verbose , UInt128 *tid)
{	
   bool changePort=false;
   bool changeIP=false;
   bool discard=false;

   StunMessage req;
   char buf[STUN_MAX_MESSAGE_SIZE];
   int len = STUN_MAX_MESSAGE_SIZE;
   
   switch (testNum)
   {
      case 1:
      case 10:
      case 11:
         break;
      case 2:
         /* changePort=true; */
         changeIP=true;
         break;
      case 3:
         changePort=true;
         break;
      case 4:
         changeIP=true;
         break;
      case 5:
         discard=true;
         break;
      default:
         printf("Test %i is unkown\n", testNum);
         return ; /* error */
   }
   
   memset(&req, 0, sizeof(StunMessage));
	
   stunBuildReqSimple( &req, username, 
                       changePort , changeIP , 
                       testNum );
	
   len = stunEncodeMessage( &req, buf, len, password,verbose );

   memcpy(tid , &(req.msgHdr.id), sizeof(req.msgHdr.id));

   sendMessage( myFd, buf, len, dest->addr, dest->port, verbose );	
}
Exemple #2
0
static void 
ice_sendtest( struct IceCheckList *checklist, struct CandidatePair *remote_candidate, Socket myFd, StunAddress4 *dest, 
              const StunAtrString *username, const StunAtrString *password, 
              UInt96 *tid)
{	
   StunMessage req;
   char buf[STUN_MAX_MESSAGE_SIZE];
   int len = STUN_MAX_MESSAGE_SIZE;
   
   memset(&req, 0, sizeof(StunMessage));

   stunBuildReqSimple( &req, username, FALSE, FALSE, 1);
   req.hasMessageIntegrity=TRUE;

   /* 7.1.1.1
   The attribute MUST be set equal to the priority that would be
   assigned, based on the algorithm in Section 4.1.2, to a peer
   reflexive candidate, should one be learned as a consequence of this
   check */
   req.hasPriority = TRUE;

   req.priority.priority = (110 << 24) | (255 << 16) | (255 << 8)
	   | (256 - remote_candidate->remote_candidate.component_id);

   /* TODO: put this parameter only for the candidate selected */
   if (remote_candidate->nominated_pair==1)
	   req.hasUseCandidate = TRUE;

   if (remote_candidate->rem_controlling==1)
	   {
		   req.hasIceControlled = TRUE;
		   req.iceControlled.value = checklist->tiebreak_value;
	   }
   else
	   {
		   req.hasIceControlling = TRUE;
		   req.iceControlling.value	= checklist->tiebreak_value;
	   }

   /* TODO: not yet implemented? */
   req.hasFingerprint = TRUE;
   
   len = stunEncodeMessage( &req, buf, len, password );

   memcpy(tid , &(req.msgHdr.tr_id), sizeof(req.msgHdr.tr_id));

   sendMessage( myFd, buf, len, dest->addr, dest->port );	
}
Exemple #3
0
void t_phone_user::send_stun_request(void) {
	if (r_stun) {
		log_file->write_report("STUN request already in progress.",
			"t_phone_user::send_stun_request", LOG_NORMAL, LOG_DEBUG);
		return;
	}

	StunMessage req;
	StunAtrString username;
	username.sizeValue = 0;
	stunBuildReqSimple(&req, username, false, false);
	r_stun = new t_client_request(user_config, &req, 0);
	MEMMAN_NEW(r_stun);
	phone->send_request(user_config, &req, r_stun->get_tuid());
	return;
}
Exemple #4
0
/* Send dummy STUN packet to open NAT ports ASAP. */
static void send_stun_packet(RtpSession *s)
{
	StunMessage msg;
	mblk_t *mp;
	char buf[STUN_MAX_MESSAGE_SIZE];
	int len = STUN_MAX_MESSAGE_SIZE;

	memset(&msg, 0, sizeof(StunMessage));
	stunBuildReqSimple(&msg, NULL, FALSE, FALSE, 1);
	len = stunEncodeMessage(&msg, buf, len, NULL);
	if (len > 0) {
		mp = allocb(len, BPRI_MED);
		memcpy(mp->b_wptr, buf, len);
		mp->b_wptr += len;
		rtp_session_sendm_with_ts(s, mp, 0);
	}
}
Exemple #5
0
static int test_stun_encode( char*buffer, size_t len, bool_t expect_fail )
{
	StunAtrString username;
	StunAtrString password;
	StunMessage req;
	memset(&req, 0, sizeof(StunMessage));
	memset(&username,0,sizeof(username));
	memset(&password,0,sizeof(password));
	stunBuildReqSimple( &req, &username, TRUE , TRUE , 11);
	len = stunEncodeMessage( &req, buffer, (unsigned int)len, &password);
	if (len<=0){
		if( expect_fail )
			ms_message("Fail to encode stun message (EXPECTED).\n");
		else
			ms_error("Fail to encode stun message.\n");
		return -1;
	}
	return (int)len;
}
Exemple #6
0
/* sends a request to a stun server */
int send_stun_request(const int udpSocket,struct sockaddr_in *stunServ)
{

  assert( sizeof(UInt8 ) == 1 );
  assert( sizeof(UInt16) == 2 );
  assert( sizeof(UInt32) == 4 );

  bool verbose = STUN_VERBOSE;
  
  //set the verbose mode 
  verbose = true;

  StunMessage req;
  memset(&req, 0, sizeof(StunMessage));

  StunAtrString username;
  StunAtrString password;
  username.sizeValue = 0;
  password.sizeValue = 0;

  /* build a stun request message  */
  /* creates a stun message struct with the given atributes  */
  stunBuildReqSimple( &req, username,
                      false , false ,
                      0x0c );

  /* buffer for the stun request  */
  char buf[STUN_MAX_MESSAGE_SIZE];
  int len = STUN_MAX_MESSAGE_SIZE;

  /* encode the stun message  */
  len = stunEncodeMessage( req, buf, len, password, verbose);

  struct iovec iov;
  iov.iov_len = len;
  iov.iov_base = buf;
  debug("Sending STUN with sendPacketFinal %d, %d!!!!!\n",len, udpSocket); 
  sendPacketFinal(udpSocket,&iov,1,stunServ);

  return 0;

}
Exemple #7
0
/* Send dummy STUN packet to open NAT ports ASAP. */
static void send_stun_packet(RtpSession *s)
{
	StunMessage msg;
	mblk_t *mp;
	char buf[STUN_MAX_MESSAGE_SIZE];
	int len = STUN_MAX_MESSAGE_SIZE;
	if (ms_is_multicast_addr((const struct sockaddr *)&s->rtcp.gs.loc_addr)) {
		ms_debug("Stun packet not sent for session [%p] because of multicast",s);
		return;
	}
	memset(&msg, 0, sizeof(StunMessage));
	stunBuildReqSimple(&msg, NULL, FALSE, FALSE, 1);
	len = stunEncodeMessage(&msg, buf, len, NULL);
	if (len > 0) {
		mp = allocb(len, BPRI_MED);
		memcpy(mp->b_wptr, buf, len);
		mp->b_wptr += len;
		ms_message("Stun packet sent for session [%p]",s);
		rtp_session_sendm_with_ts(s, mp, 0);
	}
}
Exemple #8
0
static int sendStunRequest(int sock, const struct sockaddr *server, socklen_t addrlen, int id, bool_t changeAddr){
	char buf[STUN_MAX_MESSAGE_SIZE];
	int len = STUN_MAX_MESSAGE_SIZE;
	StunAtrString username;
   	StunAtrString password;
	StunMessage req;
	int err;
	memset(&req, 0, sizeof(StunMessage));
	memset(&username,0,sizeof(username));
	memset(&password,0,sizeof(password));
	stunBuildReqSimple( &req, &username, changeAddr , changeAddr , id);
	len = stunEncodeMessage( &req, buf, len, &password);
	if (len<=0){
		ms_error("Fail to encode stun message.");
		return -1;
	}
	err=sendto(sock,buf,len,0,server,addrlen);
	if (err<0){
		ms_error("sendto failed: %s",strerror(errno));
		return -1;
	}
	return 0;
}
Exemple #9
0
static int ice_sound_send_stun_request(RtpSession *session, struct IceCheckList *checklist, uint64_t ctime)
{
	struct CandidatePair *remote_candidates = NULL;

	if (checklist==NULL)
		return 0;
	remote_candidates = checklist->cand_pairs;
	if (remote_candidates==NULL)
		return 0;

	{
		struct CandidatePair *cand_pair;
		int media_socket = rtp_session_get_rtp_socket(session);
		StunAddress4 stunServerAddr;
		StunAtrString username;
		StunAtrString password;
		bool_t res;
		int pos;

		/* prepare ONCE tie-break value */
		if (checklist->tiebreak_value==0) {
			checklist->tiebreak_value = random() * (0x7fffffffffffffffLL /0x7fff);
		}

		cand_pair=NULL;
		for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
		{
			cand_pair = &remote_candidates[pos];
			if (cand_pair->connectivity_check == ICE_PRUNED)
			{
				cand_pair=NULL;
				continue;
			}
			if (cand_pair->connectivity_check == ICE_WAITING)
				break;
			if (cand_pair->connectivity_check == ICE_IN_PROGRESS)
				break;
			if (cand_pair->connectivity_check == ICE_SUCCEEDED)
				break;
			cand_pair=NULL;
		}

		if (cand_pair==NULL)
			return 0; /* nothing to do: every pair is FAILED, FROZEN or PRUNED */

		/* start first WAITING pair */
		cand_pair=NULL;
		for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
		{
			cand_pair = &remote_candidates[pos];
			if (cand_pair->connectivity_check == ICE_PRUNED)
			{
				cand_pair=NULL;
				continue;
			}
			if (cand_pair->connectivity_check == ICE_WAITING)
				break;
			cand_pair=NULL;
		}

		if (cand_pair!=NULL)
		{
			cand_pair->connectivity_check = ICE_IN_PROGRESS;
			cand_pair->retransmission_number=0;
			cand_pair->retransmission_time=ctime+checklist->RTO;
			/* keep same rem_controlling for retransmission */
			cand_pair->rem_controlling = checklist->rem_controlling;
		}

		/* try no nominate a pair if we are ready */
		if (cand_pair==NULL && checklist->nominated_pair_index<0)
		{
			for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
			{
				cand_pair = &remote_candidates[pos];
				if (cand_pair->connectivity_check == ICE_PRUNED)
				{
					cand_pair=NULL;
					continue;
				}
				if (cand_pair->connectivity_check == ICE_SUCCEEDED)
				{
					break;
				}
				cand_pair=NULL;
			}

			/* ALWAYS accept "host" candidate that have succeeded */
			if (cand_pair!=NULL
				&& (strcasecmp(cand_pair->remote_candidate.cand_type, "host")==0))
			{
				checklist->nominated_pair_index = pos;
				cand_pair->nominated_pair = 1;
				cand_pair->connectivity_check = ICE_IN_PROGRESS;
				cand_pair->retransmission_number=0;
				cand_pair->retransmission_time=ctime+checklist->RTO;
				/* keep same rem_controlling for retransmission */
				cand_pair->rem_controlling = checklist->rem_controlling;
				/* send a new STUN with USE-CANDIDATE */
				ms_message("ice.c: nominating pair -> %i (%s:%i:%s -> %s:%i:%s) nominated=%s",
					pos,
					cand_pair->local_candidate.conn_addr,
					cand_pair->local_candidate.conn_port,
					cand_pair->local_candidate.cand_type,
					cand_pair->remote_candidate.conn_addr,
					cand_pair->remote_candidate.conn_port,
					cand_pair->remote_candidate.cand_type,
					cand_pair->nominated_pair==0?"FALSE":"TRUE");
				checklist->keepalive_time=ctime+15*1000;
			}
			else if (cand_pair!=NULL)
			{
				struct CandidatePair *cand_pair2=NULL;
				int pos2;
				for (pos2=0;pos2<pos && remote_candidates[pos2].remote_candidate.conn_addr[0]!='\0';pos2++)
				{
					cand_pair2 = &remote_candidates[pos2];
					if (cand_pair2->connectivity_check == ICE_PRUNED)
					{
						cand_pair2=NULL;
						continue;
					}
					if (cand_pair2->connectivity_check == ICE_IN_PROGRESS
						||cand_pair2->connectivity_check == ICE_WAITING)
					{
						break;
					}
					cand_pair2=NULL;
				}

				if (cand_pair2!=NULL)
				{
					/* a better candidate is still tested */
					cand_pair=NULL;
				}
				else
				{
					checklist->nominated_pair_index = pos;
					cand_pair->nominated_pair = 1;
					cand_pair->connectivity_check = ICE_IN_PROGRESS;
					cand_pair->retransmission_number=0;
					cand_pair->retransmission_time=ctime+checklist->RTO;
					/* keep same rem_controlling for retransmission */
					cand_pair->rem_controlling = checklist->rem_controlling;
					/* send a new STUN with USE-CANDIDATE */
					ms_message("ice.c: nominating pair -> %i (%s:%i:%s -> %s:%i:%s) nominated=%s",
						pos,
						cand_pair->local_candidate.conn_addr,
						cand_pair->local_candidate.conn_port,
						cand_pair->local_candidate.cand_type,
						cand_pair->remote_candidate.conn_addr,
						cand_pair->remote_candidate.conn_port,
						cand_pair->remote_candidate.cand_type,
						cand_pair->nominated_pair==0?"FALSE":"TRUE");
					checklist->keepalive_time=ctime+15*1000;
				}
			}
		}

		if (cand_pair==NULL)
		{
			/* no WAITING pair: retransmit after RTO */
			for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
			{
				cand_pair = &remote_candidates[pos];
				if (cand_pair->connectivity_check == ICE_PRUNED)
				{
					cand_pair=NULL;
					continue;
				}
				if (cand_pair->connectivity_check == ICE_IN_PROGRESS
					&& ctime > cand_pair->retransmission_time)
				{
					if (cand_pair->retransmission_number>7)
					{
						ms_message("ice.c: ICE_FAILED for candidate pair! %s:%i -> %s:%i",
							cand_pair->local_candidate.conn_addr,
							cand_pair->local_candidate.conn_port,
							cand_pair->remote_candidate.conn_addr,
							cand_pair->remote_candidate.conn_port);

						cand_pair->connectivity_check = ICE_FAILED;
						cand_pair=NULL;
						continue;
					}

					cand_pair->retransmission_number++;
					cand_pair->retransmission_time=ctime+checklist->RTO;
					break;
				}
				cand_pair=NULL;
			}
		}

		if (cand_pair==NULL)
		{
			if (checklist->nominated_pair_index<0)
				return 0;

			/* send STUN indication each 15 seconds: keepalive */
			if (ctime>checklist->keepalive_time)
			{
				checklist->keepalive_time=ctime+15*1000;
				for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
				{
					cand_pair = &remote_candidates[pos];
					if (cand_pair->connectivity_check == ICE_SUCCEEDED)
					{
						res = stunParseServerName(cand_pair->remote_candidate.conn_addr,
							&stunServerAddr);
						if ( res == TRUE )
						{
							StunMessage req;
							char buf[STUN_MAX_MESSAGE_SIZE];
							int len = STUN_MAX_MESSAGE_SIZE;
							stunServerAddr.port = cand_pair->remote_candidate.conn_port;
							memset(&req, 0, sizeof(StunMessage));
							stunBuildReqSimple( &req, NULL, FALSE, FALSE, 1);
							req.msgHdr.msgType = (STUN_METHOD_BINDING|STUN_INDICATION);
							req.hasFingerprint = TRUE;
							len = stunEncodeMessage( &req, buf, len, NULL);
							sendMessage( media_socket, buf, len, stunServerAddr.addr, stunServerAddr.port );
						}
					}
				}
			}

			return 0;
		}

		username.sizeValue = 0;
		password.sizeValue = 0;

		/* username comes from "ice-ufrag" (rfrag:lfrag) */
		/* ufrag and pwd are in first row only */
		snprintf(username.value, sizeof(username.value), "%s:%s",
			checklist->rem_ice_ufrag,
			checklist->loc_ice_ufrag);
		username.sizeValue = (uint16_t)strlen(username.value);


		snprintf(password.value, sizeof(password.value), "%s",
			checklist->rem_ice_pwd);
		password.sizeValue = (uint16_t)strlen(password.value);


		res = stunParseServerName(cand_pair->remote_candidate.conn_addr,
			&stunServerAddr);
		if ( res == TRUE )
		{
			ms_message("ice.c: STUN REQ (%s) -> %i (%s:%i:%s -> %s:%i:%s) nominated=%s",
				cand_pair->nominated_pair==0?"":"USE-CANDIDATE",
				pos,
				cand_pair->local_candidate.conn_addr,
				cand_pair->local_candidate.conn_port,
				cand_pair->local_candidate.cand_type,
				cand_pair->remote_candidate.conn_addr,
				cand_pair->remote_candidate.conn_port,
				cand_pair->remote_candidate.cand_type,
				cand_pair->nominated_pair==0?"FALSE":"TRUE");
			stunServerAddr.port = cand_pair->remote_candidate.conn_port;
			ice_sendtest(checklist, cand_pair, media_socket, &stunServerAddr, &username, &password,
				&(cand_pair->tid));
		}
	}

	return 0;
}
bool get_stun_binding(t_user *user_config, unsigned short src_port, unsigned long &mapped_ip,
	unsigned short &mapped_port, int &err_code, string &err_reason)
{
	list<t_ip_port> destinations = 
		user_config->get_stun_server().get_h_ip_srv("udp");
	
	if (destinations.empty()) {
		// Cannot resolve STUN server address.
		log_file->write_header("::get_stun_binding", LOG_NORMAL, LOG_CRITICAL);
		log_file->write_raw("Failed to resolve: ");
		log_file->write_raw(user_config->get_stun_server().encode());
		log_file->write_endl();
		log_file->write_raw("Return internal STUN bind error: 404 Not Found");
		log_file->write_endl();
		log_file->write_footer();
		
		err_code = 404;
		err_reason = "Not Found";
		return false;
	}
	
	int num_transmissions = 0;
	int wait_intval = DUR_STUN_START_INTVAL;

	t_socket_udp sock(src_port);
	sock.connect(destinations.front().ipaddr, destinations.front().port);
		
	// Build STUN request
	char buf[STUN_MAX_MESSAGE_SIZE + 1];
	StunMessage req_bind;
	StunAtrString stun_null_str;
	stun_null_str.sizeValue = 0;	
	stunBuildReqSimple(&req_bind, stun_null_str, false, false);	
	char req_msg[STUN_MAX_MESSAGE_SIZE];
	int req_msg_size = stunEncodeMessage(req_bind, req_msg, 
		STUN_MAX_MESSAGE_SIZE, stun_null_str, false);
		
	// Send STUN request and retransmit till a response is received.
	while (num_transmissions < STUN_MAX_TRANSMISSIONS) {
		bool ret;

		try {
			sock.send(req_msg, req_msg_size);
		}
		catch (int err) {
			// Socket error (probably ICMP error)
			// Failover to next destination
			log_file->write_report("Send failed. Failover to next destination.",
					"::get_stun_binding");	
						
			destinations.pop_front();
			if (destinations.empty()) {
				log_file->write_report("No next destination for failover.",
					"::get_stun_binding");
				break;
			}
			
			num_transmissions = 0;
			wait_intval = DUR_STUN_START_INTVAL;
			sock.connect(destinations.front().ipaddr, destinations.front().port);
			continue;
		}
		
		log_file->write_header("::get_stun_binding", LOG_STUN);
		log_file->write_raw("Send to: ");
		log_file->write_raw(h_ip2str(destinations.front().ipaddr));
		log_file->write_raw(":");
		log_file->write_raw(destinations.front().port);
		log_file->write_endl();
		log_file->write_raw(stunMsg2Str(req_bind));
		log_file->write_footer();
			
		try {
			ret = sock.select_read(wait_intval);
		}
		catch (int err) {
			// Socket error (probably ICMP error)
			// Failover to next destination
			log_file->write_report("Select failed. Failover to next destination.",
					"::get_stun_binding");	
						
			destinations.pop_front();
			if (destinations.empty()) {
				log_file->write_report("No next destination for failover.",
					"::get_stun_binding");
				break;
			}
			
			num_transmissions = 0;
			wait_intval = DUR_STUN_START_INTVAL;
			sock.connect(destinations.front().ipaddr, destinations.front().port);
			continue;
		}
			
		if (!ret) {
			// Time out
			num_transmissions++;
			if (wait_intval < DUR_STUN_MAX_INTVAL) {
				wait_intval *= 2;
			}
			continue;
		}
			
		// A message has been received
		int resp_msg_size;
		try {
			resp_msg_size = sock.recv(buf, STUN_MAX_MESSAGE_SIZE + 1);
		}
		catch (int err) {
			// Socket error (probably ICMP error)
			// Failover to next destination
			log_file->write_report("Recv failed. Failover to next destination.",
					"::get_stun_binding");	
						
			destinations.pop_front();
			if (destinations.empty()) {
				log_file->write_report("No next destination for failover.",
					"::get_stun_binding");
				break;
			}
			
			num_transmissions = 0;
			wait_intval = DUR_STUN_START_INTVAL;
			sock.connect(destinations.front().ipaddr, destinations.front().port);
			continue;
		}
			
		StunMessage resp_bind;
		
		if (!stunParseMessage(buf, resp_msg_size, resp_bind, false)) {
			log_file->write_report(
				"Received faulty STUN message", "::get_stun_binding", 
					LOG_STUN);
			num_transmissions++;
			if (wait_intval < DUR_STUN_MAX_INTVAL) {
				wait_intval *= 2;
			}
			continue;
		}
		
		log_file->write_header("::get_stun_binding", LOG_STUN);
		log_file->write_raw("Received from: ");
		log_file->write_raw(h_ip2str(destinations.front().ipaddr));
		log_file->write_raw(":");
		log_file->write_raw(destinations.front().port);
		log_file->write_endl();
		log_file->write_raw(stunMsg2Str(resp_bind));
		log_file->write_footer();
		
		// Check if id in msgHdr matches
		if (!stunEqualId(resp_bind, req_bind)) {
			num_transmissions++;
			if (wait_intval < DUR_STUN_MAX_INTVAL) {
				wait_intval *= 2;
			}
			continue;
		}
				
		if (resp_bind.msgHdr.msgType == BindResponseMsg && 
		    resp_bind.hasMappedAddress) {
		    	// Bind response received
			mapped_ip = resp_bind.mappedAddress.ipv4.addr;
			mapped_port = resp_bind.mappedAddress.ipv4.port;
			return true;
		}
			
		if (resp_bind.msgHdr.msgType == BindErrorResponseMsg &&
		    resp_bind.hasErrorCode) 
		{
			// Bind error received
			err_code = resp_bind.errorCode.errorClass * 100 +
				   resp_bind.errorCode.number;
			char s[STUN_MAX_STRING + 1];
			strncpy(s, resp_bind.errorCode.reason, STUN_MAX_STRING);
			s[STUN_MAX_STRING] = 0;
			err_reason = s;
			return false;
		}
			
		// A wrong response has been received.
		log_file->write_report(
			"Invalid STUN response received", "::get_stun_binding", 
				LOG_NORMAL);

		err_code = 500;
		err_reason = "Server Error";
		return false;
	}
		
	// Request timed out
	log_file->write_report("STUN request timeout", "::get_stun_binding", 
			LOG_NORMAL);
				
	err_code = 408;
	err_reason = "Request Timeout";
	return false;
}