Kamailio as SBC for MS Teams

Este post complementa con un ejemplo mínimo pero funcional de lo expuesto en Kamailio as SBC for MS Teams.

Escenario confirmado.

flowchart LR MSTeams["MS Teams v.2023.6.21.5 "] Kamailio["Kamailio v5.4.4 RTPEngine 11.3.1.4 "] PBX["FreeSWITCH v1.10.9 "] MSTeams ---|TLS/PUBLIC IP| Kamailio Kamailio ---|UDP/PUBLIC IP| PBX

Funcionalidades confirmadas:

  • Llamadas MSTeams a PBX
  • Llamadas PBX a MSTeams
  • MSTeams Hold
  • MSTeams Park
  • MSTeams Unpark

Para que esta configuracion sea efectiva debes conectar Kamailio a MS Teams y una vez confirmes que MS Teams detecta el Kamailio puedes proceder a usar la configuracion entregada.

kamailio/kamailio.cfg

#!KAMAILIO
#
# Asesorias y Consultorias a contacto@bit4bit.in


# ACTUALIZAR LOS VALORES A CONTINUACION
#!substdef "!SIPS_PORT!7062!g"
#!substdef "!SIP_PORT!5073!g"
#!substdef "!PBX_IP!3.3.3.3!g"
#!substdef "!PBX_SIP_PORT!5060!g"
#!substdef "!EXTERNAL_IP!2.2.2.2!g"
#!substdef "!EXTERNAL_FQDN!demo.bit4bit.in!g"

debug=2
log_stderror=no
log_facility=LOG_LOCAL0
log_prefix="{$mt $hdr(CSeq) $ci} "
children=8
alias=EXTERNAL_FQDN:SIPS_PORT
alias=EXTERNAL_FQDN:SIP_PORT
listen=tls:EXTERNAL_IP:SIPS_PORT advertise EXTERNAL_FQDN:SIPS_PORT
listen=udp:EXTERNAL_IP:SIP_PORT advertise EXTERNAL_FQDN:SIP_PORT
enable_tls=yes
tls_max_connections=2048
enable_sctp=no

loadmodule "kex.so"
loadmodule "corex.so"
loadmodule "tm.so"
loadmodule "tmx.so"
loadmodule "sl.so"
loadmodule "rr.so"
loadmodule "pv.so"
loadmodule "maxfwd.so"
loadmodule "textops.so"
loadmodule "textopsx.so"
loadmodule "siputils.so"
loadmodule "xlog.so"
loadmodule "ctl.so"
loadmodule "dispatcher.so"
loadmodule "rtpengine.so"
loadmodule "nathelper.so"
loadmodule "tls.so"

modparam("rtpengine", "rtpengine_sock", "udp:127.0.0.1:2223")
modparam("tls", "config", "/etc/kamailio/tls.cfg")
modparam("dispatcher", "list_file", "/etc/kamailio/dispatcher.list")
modparam("dispatcher", "ds_probing_mode", 1)
modparam("dispatcher", "ds_ping_interval", 10)
	
####### Routing Logic ########

request_route {
	if (!mf_process_maxfwd_header("10")) {
		sl_send_reply("483","Too Many Hops");
		exit;
	}

	if(is_method("OPTIONS") && uri==myself && $rU==$null) {
		sl_send_reply("200","Keepalive");
		exit;
	}

    # FROM MSTEAMS
	if($hdr(User-Agent) =~ "Microsoft.PSTNHub") {
		$du = "sip:PBX_IP:PBX_SIP_PORT;transport=udp";
    }
    # TO MSTEAMS
    else {
		$du = "sip:sip.pstnhub.microsoft.com;transport=tls";
    }

    if ($rU==$null) {
		sl_send_reply("484","Address Incomplete");
		exit;
    }

    record_route();

    route(RELAY);
  }

route[RELAY] {
	route(REFER);
  
	if (is_method("INVITE|BYE|CANCEL")) {
		if(!t_is_set("branch_route")) t_on_branch("MANAGE_BRANCH");
	}
	if (is_method("INVITE")) {
		if(!t_is_set("onreply_route")) t_on_reply("MANAGE_REPLY");
	}

	if (!t_relay()) {
		sl_reply_error();
	}
	
	exit;
}

route[RTPMANAGE] {
	if (!has_body("application/sdp")) {
		return;
	}


	if($dd =~ "sip.pstnhub.microsoft.com") {
		rtpengine_offer("trust-address replace-origin replace-session-connection ICE=force transcode-PCMU transcode-G722 RTP/SAVP");
	} else {
		rtpengine_answer("trust-address replace-origin replace-session-connection ICE=remove RTP/AVP");
	}
	
	return;
}

route[RTPREPLY] {
	if (!has_body("application/sdp")) {
		return;
	}

	if ($fd == "PBX_IP") {
		rtpengine_offer("trust-address replace-origin replace-session-connection ICE=remove RTP/AVP");
	} else {
		rtpengine_answer("trust-address replace-origin replace-session-connection ICE=force transcode-PCMU transcode-G722 RTP/SAVP");
	}
	
	return;
}

route[REFER] {
	exclude_hf_value("Allow", "REFER");
	return;
}

branch_route[MANAGE_BRANCH] {
	route(RTPMANAGE);
}

onreply_route[MANAGE_REPLY] {
	route(REFER);

	if(status=~"[12][0-9][0-9]") {
		route(RTPREPLY);
	}
}

event_route[tm:local-request] {
	if (is_method("OPTIONS") && $ru =~ "pstnhub.microsoft.com") {
		append_hf("Contact: <sip:$fd:SIPS_PORT;transport=tls>\r\n");
	}
}

kamailio/tls.cfg

[server:default]
method = TLSv1.2+
verify_certificate = no
require_certificate = no
private_key = HERE YOUR PRIVATE KEY
certificate = HERE YOUR CERTIFICATE

[client:default]
method = TLSv1.2+
verify_certificate = no
require_certificate = no
private_key = HERE YOUR PRIVATE KEY
certificate = HERE YOUR CERTIFICATE

kamailio/dispatcher.list

# setid(integer) destination(sip uri) flags (integer, optional), priority(int,opt), attrs (str,optional)
1 sip:sip.pstnhub.microsoft.com;transport=tls 0 3 socket=tls:HERE EXTERNAL IP:HERE SIPS PORT;ping_from=sip:HERE EXTERNAL FQDN
1 sip:sip2.pstnhub.microsoft.com;transport=tls 0 2 socket=tls:HERE EXTERNAL IP:HERE SIPS PORT;ping_from=sip:HERE EXTERNAL FQDN
1 sip:sip3.pstnhub.microsoft.com;transport=tls 0 1 socket=tls:HERE EXTERNAL IP:HERE SIPS PORT;ping_from=sip:HERE EXTERNAL FQDN

Para escenarios más complejos o funcionalidades no presentes puedes contactarme a contacto@bit4bit.in.

Referencias