﻿---
title: "Kamailio as SBC for MS Teams"
date: 2023-06-25T09:11:44-05:00
draft: false
---

Este post complementa con un ejemplo mínimo pero funcional de lo expuesto en [Kamailio as SBC for MS Teams](https://skalatan.de/en/blog/kamailio-sbc-teams).

Escenario confirmado.
```mermaid
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:


* [X] Llamadas MSTeams a PBX 
* [X] Llamadas PBX a MSTeams
* [X] MSTeams Hold
* [X] MSTeams Park
* [X] MSTeams Unpark

Para que esta configuracion sea efectiva debes conectar [Kamailio a MS Teams](https://skalatan.de/en/blog/kamailio-sbc-teams) y
una vez confirmes que MS Teams detecta el Kamailio puedes proceder a usar la configuracion entregada.

**kamailio/kamailio.cfg**
```kamailio @mdtoapp file: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**
```kamailio @mdtoapp file: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**
```csv @mdtoapp file: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
```


<!--
```sh @mdtoapp @execute
/usr/sbin/kamailio -d 0 -D -c -f kamailio/kamailio.cfg
```
-->

Para escenarios más complejos o funcionalidades no presentes puedes contactarme a [contacto@bit4bit.in](mailto:contacto@bit4bit.in).

## Referencias

- [Kamailio as SBC for MS Teams](https://skalatan.de/en/blog/kamailio-sbc-teams).
- [DSIPRouter kamailio.cfg](https://github.com/dOpensource/dsiprouter/blob/master/kamailio/configs/kamailio.cfg)
