Opensips NAT Script com RTPproxy

De opensipsbrasil - wiki
Ir para navegação Ir para pesquisar

Prefacio

Nat é uma questão que normalmente da um pouco de trabalho para entender no opensips, é bem diferente daquilo que estamos acostumados no asterisk por exemplo onde basta ativar uma flag e pronto tudo acontece.

Não vou demonstrar aqui como instalar o opensips ou rtpproxy, apenas demonstro um arquivo de configuração todo comentado com uma configuração minima para aceitar registros e encaminhar chamadas de um usuario para outro atrás de nat

O script não precisa de usuario previamente configurado, qualquer autenticacao enviada ele ira aceitar, e a cada restart voce tem que se registrar novamente pois a informacao esta toda na memoria, o proposito é unicamente demonstrar as questoes de nat

opensips.cfg

###################################
# Este script tem por intuito demonstrar a configuracao
# de um script de roteamento com NAT
#
###################################


####### Parametros Globais #########

debug=3
log_stderror=no
log_facility=LOG_LOCAL0

fork=yes
children=4

/* Para fazer debug descomente as linhas abaixo */
#debug=6
#fork=no
#log_stderror=yes

auto_aliases=no

# IP no qual iremos aguardar por requisicoes
listen=udp:___IP_DO_OPENSIPS_AQUI___:5060  

# Desativacao do suporte a SIP via TCP
disable_tcp=yes

# Desativacao do suporte a TLS (criptografia) na sinalizacao
disable_tls=yes


####### Secao de Modulos ########

# Definicao do diretorio de modulos
mpath="/usr//lib64/opensips/modules/"

#### Modulo de sinalizacao 
loadmodule "signaling.so"

#### Modulo stateless 
loadmodule "sl.so"

#### Modulo para suporte a transacoes 
loadmodule "tm.so"
modparam("tm", "fr_timer", 5)
modparam("tm", "fr_inv_timer", 30)
modparam("tm", "restart_fr_on_each_reply", 0)
modparam("tm", "onreply_avp_mode", 1)

#### Modulo para Record Route 
loadmodule "rr.so"
modparam("rr", "append_fromtag", 0)

#### Modulo para deteccao de loop (Max forward) 
loadmodule "maxfwd.so"

#### Modulo para mensagens de operaca
loadmodule "sipmsgops.so"

#### Modulo para ativacao do gerenciamento via FIFO 
loadmodule "mi_fifo.so"
modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")
modparam("mi_fifo", "fifo_mode", 0666)

#### Modulo URI 
loadmodule "uri.so"
modparam("uri", "use_uri_table", 0)

#### Modulo para localizacao de usuario 
loadmodule "usrloc.so"
modparam("usrloc", "nat_bflag", "NAT")
modparam("usrloc", "db_mode",   0)

#### Modulo para suporte a registros
loadmodule "registrar.so"


#### Modulo para auxilio de NAT
loadmodule "nathelper.so"
modparam("nathelper", "natping_interval", 10)
modparam("nathelper", "natping_socket", "___IP_DO_OPENSIPS_AQUI___:5060")
# o parametro abaixo armazena a uri do usuario quando chamada
# a funcao fix_nated_register
modparam("nathelper", "received_avp", "$avp(42)")
#modparam("nathelper", "sipping_bflag", "SIP_PING_FLAG")
modparam("nathelper", "sipping_from", "sip:pinger@___IP_DO_OPENSIPS_AQUI___")
# o parametro abaixo define qual o formato do pacote a ser enviado
# ele pode ser OPTIONS (default) ou INFO
modparam("nathelper", "sipping_method", "OPTIONS")


#### Modulo rtpproxy (forcar o audio atraves do opensips)
loadmodule "rtpproxy.so"
modparam("rtpproxy", "rtpproxy_sock", "udp:localhost:7890")


####### Logica de roteamento ########

#  Sessao principal

route{

	# Esta e uma configuracao minima recomendada para 
	# previnir loops
	if (!mf_process_maxfwd_header("10")) {
		sl_send_reply("483","Too Many Hops");
		exit;
	}



	if (has_totag()) {
		# Requisicao previamente processada
		if (loose_route()) {
			xlog("Estamos em loose_route");
			if (is_method("INVITE")) {
				record_route();
			}

			route(relay);
		} else {
			if ( is_method("ACK") ) {
				if ( t_check_trans() ) {
					t_relay();
					exit;
				} else {
					xlog("Nao estamos em loose, temos totag, metodo nao ack [ $rm ] ");
					# Transacao nao encontrada , vamos encerrar o roteamento
					exit;
				}
			}
			# Rota nao trata de encerramento e nem a resposta
			# de requisicao, entao enviamos um 404
			sl_send_reply("404","Not here");
		}
		exit;
	}

		# Processando requisicao de cancelamento 
	if (is_method("CANCEL"))
	{
		if (t_check_trans())
			t_relay();
		exit;
	}

	t_check_trans();

	
	if ( !(is_method("REGISTER")  ) ) {
		# Verificando se o from e um usuario valido
		if (from_uri==myself)
		{
		} else {
			# From nao e usuario valido entao procedemos
			# para recusa pois o destino nao somos nos
			if (!uri==myself) {
				send_reply("403","Rely forbidden");
				exit;
			}
		}
	}

	# Checando pacotes com rotas pre-carregadas 
	if (loose_route()) {
		xlog("L_ERR",
		"Attempt to route with preloaded Route's [$fu/$tu/$ru/$ci]");
		if (!is_method("ACK"))
			sl_send_reply("403","Preload Route denied");
		exit;
	}

	# Se metodo nao e register ou message entao gravamos a rota 
	if (!is_method("REGISTER|MESSAGE"))
		record_route();


	# Nao somos o destino da requisicao entao acrescentamos 
	# uma informacao para identificar como saida e enviamos para relay	
	if (!uri==myself) {
		append_hf("P-hint: outbound\r\n"); 
		route(relay);
	}

	# Requisicoes de PUBLISH e SUBSCRIBE
	# Nao vamos tratar neste documento 
	if (is_method("PUBLISH|SUBSCRIBE"))
	{
		sl_send_reply("503", "Service Unavailable");
		exit;
	}

	# Tratamento para metodo register
	if (is_method("REGISTER"))
	{

		# Aqui estamos recebendo um pedido de register
		# vamos executar fix_nated_register
		fix_nated_register();
		fix_nated_contact();

		# Este script e apenas ilustrativo , nao vamos criar usuarios
		# qualquer requisicao que chegue no mesmo sera aceita como valida
		# (registro) e a informacao sera salva
		if (!save("location"))
			sl_reply_error();

		exit;
	}

	if ($rU==NULL) {
		#requisicao com endereco incompleto
		sl_send_reply("484","Address Incomplete");
		exit;
	}

	# Este processamento so vai acontecer quando for uma chamada
	# com destino a nosso opensips, neste caso ele ira 
	# verificar se o usuario esta registrado, se estiver
	# ele apenas enviara para relay se nao ele vai responder
	# com uma mensagem de 404
	if (!lookup("location","m")) {
		t_newtran();
		t_reply("404", "Not Found");
		exit;
	} 

	# Enviando para relay 
	route(relay);
}


route[relay] {
	# verificamos se trata-se de um invite
	# para entao podermos definir as funcoes
	# para resposta dos pacotes
	if (is_method("INVITE")) {
		# Para cada perna adicionada ele chama
		# a rota abaixo ( branch_route(per_branch_ops) )
		t_on_branch("per_branch_ops");

		# Para cada reply recebido ele executa a rota abaixo
		# on_reply_route(handle_nat)
		t_on_reply("handle_nat");

		# Chamadas que nao completaram sao procesadas
		# pela failure_route(missed_call)
		t_on_failure("missed_call");


		# Vamos tentar identificar se o usuario esta atras de nat
		# fazemos isso no invite porque assim que recebemos 
		# a requisicao procedemos com a correcao se necessaria
		if(nat_uac_test("127")){
			# Usuario identificado como atras de nat
			xlog("Usuario atras de nat em handle nat");
			fix_nated_contact();
		}

		# Vamos verificar se temos cabecalho rtp e entao proceder com o rtpproxy
		if(has_body("application/sdp")){
			xlog("Temos sdp no body para $rm");
			rtpproxy_offer();
		}
	

	}

	# Loose route quando tudo ok envia cancel e by para ca
	# entao aqui vamos desligar o rtp proxy
	if(is_method("CANCEL|BYE")){
		unforce_rtp_proxy();
	}


	# Aqui finalmente fazemos o relay do pacote
	# se nao conseguirmos fazer o relay entao
	# retornarmos erro 500 como erro interno
	if (!t_relay()) {
		send_reply("500","Internal Error");
	};
	exit;
}


branch_route[per_branch_ops] {
	# Nova perna adicionada a chamada
	xlog("new branch at $ru\n");
}


onreply_route[handle_nat] {
	# Recebemos resposta do pacote	
	xlog("incoming reply\n");
	
	# Verificamos aqui se esta requisicao possui SDP
	if(is_method("ACK") && has_body("application/sdp")){
		# Atendemos no rtpproxy
		rtpproxy_answer();

	}else if(has_body("application/sdp")){
		# possuindo sdp vamos re-escrever a informacao
		#fix_nated_sdp("2");
		rtpproxy_offer();	
	}


	# Vamos tentar identificar se o usuario esta atras de nat
	# executamos neste nivel pois aqui sera executado
	# no momento que recebemos resposta, assim garantimos
	# que em todos os casos manipularemos o nat
	if(nat_uac_test("127")){
		# Usuario identificado como atras de nat
		xlog("Usuario atras de nat em handle nat");
		fix_nated_contact();
	}
}


failure_route[missed_call] {
	# Chamada nao completada
	# verificamos se é um cancess e chamamos
	# a funcao responsavel por isso e entao
	# encerramos
	if (t_was_cancelled()) {
		exit;
	}

}