Archivo de la etiqueta: OpenSIPS

SIP2SIP: SIP gratis para las masas

Hace unos pocos días tuve la oportunidad de participar nuevamente en el voip2day, con la charla “SIP2SIP: SIP gratis para las masas”.

El evento fue increíble, ¡sin duda la mejor edición hasta la fecha! Pude reencontrarme con antiguos amigos, hacer nuevos y desvirtualizar a otros cuantos 🙂

Muchas gracias a los organizadores y sponsors por seguir trabajando en hacer un voip2day mejor cada año.

Aquí os dejo mi presentación, para los que pudierais asistir:


¡Nos vemos el año que viene!

 

ElastixWorld: OpenSIPS Workshop

Además de nuestras respectivas presentaciones, Adrian y yo tuvimos la ocasión de impartir un workshop sobre OpenSIPS.

OpenSIPS no es precisamente fácil de aprender, ya que ofrece control a muy bajo nivel, por lo que nos esperábamos una asistencia bastante reducida. Cual fue nuestra sorpresa cuando vimos que no paraba de venir gente y que muchos incluso estaban de pie escuchando, ¡gracias a todos los asistentes!

opensips_workshop

Para los que no pudieron estar, aquí está la presentación que utilizamos, en la que comentamos algunas buenas prácticas para la administración de OpenSIPS, seguridad, etc.


De nuevo, gracias a todos los asistentes y a la organización, ¡el año que viene habrá más!

ACTUALIZACIÓN: Gracias a Eternal por grabar el vídeo, aqúi lo tenéis en YouTube:

ITExpo East y FOSDEM, ¡allá vamos!

Con el año nuevo se inaugura la temporada de conferencias, concretamente con 2 la semana que viene: ITExpo East (en Miami) y FOSDEM.

Ya estuve en ITExpo en 2010, pero solo como expositor, mientras que éste año además soy speaker 🙂 Dentro del ITExpo se organiza el Asterisk World, y allí daré una charla titulada “SIP Conferencing Reloaded” donde comentaré la historia de SylkServer y qué características debería de tener un servidor de conferencias SIP de nuestro tiempo.

En esta ocasión, además, estaremos junto a otras empresas en el OpenSIPS Pavillion, si alguno andáis por allá ¡acercaos a saludar!

Y menos 48 horas después del ITExpo… ¡al FOSDEM!

Tuve la ocasión de asistir al FOSDEM por primera vez el año pasado y la verdad es que se lo recomiendo a todo el mundo. Si quieres ponerte en contacto con el desarrollador principal de casi cualquier proyecto Open Source FOSDEM es el sitio al que acudir. Este año también me han aceptado como speaker así que tendré mi oportunidad de evangelizar en el uso de SIP más llá de la VoIP, con la charla “SIP beyond VoIP”.

Aunque llegaré medio muerto al FOSDEM (tras el ITExpo, viaje, jet-lag, etc) tengo 1001 ganas de ir y encontrarme con gente que hace mucho que no veo y así poder charlar / flamear un rato. Por si aún os lo estáis pensando, aquí está el programa de la “Telephony and Communications Devroom”.

Esperad un post con detalles de ambos eventos y dispositivas en unos días. Y a ver si me pongo a escribir algo técnico de nuevo…

Mandando comandos a OpenSIPS con mi_datagram

OpenSIPS dispone de diversos módulos mediante los cuales podemos enviar comandos para realizar determinadas acciones o consultar información. Podemos interactuar con OpenSIPS mediante un socket (mi_datagram) un fifo (mi_fifo) o XML-RPC (mi_xmlrpc).

Para mandar comandos sencillos podemos utilizar la herramienta de consola que ya viene con OpenSIPS opensipsctl, pero el fifo al que nos conectamos viene dado por el valor almacenado en un fichero (por defecto en /etc/opensips/opensipsctlrc), por lo tanto no es muy flexible si tenemos varias instancias de OpenSIPS corriendo en la misma máquina.

En MediaProxy y CallControl hacemos uso del módulo mi_datagram, para comunicarnos con OpenSIPS e indicarle que ha de terminar un diálogo, por ejemplo, por lo que pensé en reutilizar ese código para poder mandar comandos más fácilmente desde una interfaz de consola.

El resultado:

Un script que toma el comando que le pasemos por la línea de comando, lo formatea correctamente y lo envía al socket de OpenSIPS. Es bastante simple, pero nunca había probado el módulo stdio de Twisted, que permite hacer IO asíncrona de la entarda estándar, y ésta era una buena ocasión para probarlo. 😉

Google utiliza OpenSIPS y YATE en Google Voice

A ver si al final va Google y permite usar SIP con Google Voice… aunque sea con números de teléfono.

Resulta que si sabemos el número de GV de un usuario le podemos ayer le podíamos llamar de manera gratuita por SIP de la siguiente manera:

sip:+14049397606@sip.voice.google.com (el de ejemplo es mi número)

Al comprobar que esto era cierto, lo primero que se me ocurrió fue hacer una consulta DNS y ver si tenían registros DNS SRV:

saghul@hal:~$ dig srv _sip._udp.sip.voice.google.com

; <<>> DiG 9.7.2-P3 <<>> srv _sip._udp.sip.voice.google.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 45638
;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 13, ADDITIONAL: 0

;; QUESTION SECTION:
;_sip._udp.sip.voice.google.com.        IN      SRV

;; ANSWER SECTION:
_sip._udp.sip.voice.google.com. 82958 IN SRV    40 1 5060 alt3.voice-sip.l.google.com.
_sip._udp.sip.voice.google.com. 82958 IN SRV    50 1 5060 alt4.voice-sip.l.google.com.
_sip._udp.sip.voice.google.com. 82958 IN SRV    10 1 5060 voice-sip.l.google.com.
_sip._udp.sip.voice.google.com. 82958 IN SRV    20 1 5060 alt1.voice-sip.l.google.com.
_sip._udp.sip.voice.google.com. 82958 IN SRV    30 1 5060 alt2.voice-sip.l.google.com.

;; AUTHORITY SECTION:
com.                    83093   IN      NS      d.gtld-servers.net.
com.                    83093   IN      NS      i.gtld-servers.net.
com.                    83093   IN      NS      c.gtld-servers.net.
com.                    83093   IN      NS      a.gtld-servers.net.
com.                    83093   IN      NS      j.gtld-servers.net.
com.                    83093   IN      NS      e.gtld-servers.net.
com.                    83093   IN      NS      k.gtld-servers.net.
com.                    83093   IN      NS      m.gtld-servers.net.
com.                    83093   IN      NS      l.gtld-servers.net.
com.                    83093   IN      NS      b.gtld-servers.net.
com.                    83093   IN      NS      h.gtld-servers.net.
com.                    83093   IN      NS      f.gtld-servers.net.
com.                    83093   IN      NS      g.gtld-servers.net.

;; Query time: 0 msec
;; SERVER: 192.168.99.116#53(192.168.99.116)
;; WHEN: Mon Mar  7 22:45:44 2011
;; MSG SIZE  rcvd: 502

Parece que si, ¡bien! Ahora probemos a mandarle un OPTIONS:

saghul@hal:~$ sipsak -vvv -s sip:test@sip.voice.google.com
No SRV record: _sip._tcp.sip.voice.google.com
using SRV record: _sip._udp.sip.voice.google.com:5060
fqdnhostname: 192.168.99.53
warning: need raw socket (root privileges) to receive all ICMP errors
our Via-Line: Via: SIP/2.0/UDP 192.168.99.53:53335;branch=z9hG4bK.40128570;rport;alias

New message with Via-Line:
OPTIONS sip:test@sip.voice.google.com SIP/2.0
Via: SIP/2.0/UDP 192.168.99.53:53335;branch=z9hG4bK.40128570;rport;alias
From: sip:sipsak@192.168.99.53:53335;tag=626043f9
To: sip:test@sip.voice.google.com
Call-ID: 1650476025@192.168.99.53
CSeq: 1 OPTIONS
Contact: sip:sipsak@192.168.99.53:53335
Content-Length: 0
Max-Forwards: 70
User-Agent: sipsak 0.9.6
Accept: text/plain

request:
OPTIONS sip:test@sip.voice.google.com SIP/2.0
Via: SIP/2.0/UDP 192.168.99.53:53335;branch=z9hG4bK.40128570;rport;alias
From: sip:sipsak@192.168.99.53:53335;tag=626043f9
To: sip:test@sip.voice.google.com
Call-ID: 1650476025@192.168.99.53
CSeq: 1 OPTIONS
Contact: sip:sipsak@192.168.99.53:53335
Content-Length: 0
Max-Forwards: 70
User-Agent: sipsak 0.9.6
Accept: text/plain

send to: UDP:74.125.95.192:5060

message received
received from: UDP:74.125.95.192:5060
SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.99.53:53335;branch=z9hG4bK.40128570;rport=64017;alias;received=62.131.6.55
From: sip:sipsak@192.168.99.53:53335;tag=626043f9
To: sip:test@sip.voice.google.com;tag=b6af3ec14a5583bc5e0a35f4053f902f.d201
Call-ID: 1650476025@192.168.99.53
CSeq: 1 OPTIONS
Server: OpenSIPS (1.6.2-notls (x86_64/linux))
Content-Length: 0

Ey, ¡si nos ha contestado un OpenSIPS! Esto pinta bien, vamos a probar un INVITE:

INVITE sip:+14049397606@sip.voice.google.com SIP/2.0
Via: SIP/2.0/UDP 192.168.99.53:39101;rport;branch=z9hG4bKPjuwdK-wRVFy7dsJD4xYtZSpD4vIKEcKRC
Max-Forwards: 70
From: "Saúl" ;tag=9rNjdJVXH-y-5I8i1pzaTQ2lJnH83ktq
To: 
Contact: 
Call-ID: xvpzBMnseFltW2KzzbBAO4DX-ILHionW
CSeq: 15643 INVITE
Allow: SUBSCRIBE, NOTIFY, PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, MESSAGE, REFER
Supported: 100rel, norefersub
User-Agent: sipsimple 0.17.1
Content-Type: application/sdp
Content-Length:   281

v=0
o=- 3508522483 3508522483 IN IP4 192.168.99.53
s=sipsimple 0.17.1
c=IN IP4 192.168.99.53
t=0 0
m=audio 50026 RTP/AVP 9 8 0 101
a=rtcp:50027
a=rtpmap:9 G722/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=sendrecv

--

2011-03-07 22:34:43.943855: RECEIVED: Packet 2, +0:00:00.150306
74.125.95.192:5060 -(SIP over UDP)-> 192.168.99.53:39101
SIP/2.0 100 Giving a try
Via: SIP/2.0/UDP 192.168.99.53:39101;rport=61928;branch=z9hG4bKPjuwdK-wRVFy7dsJD4xYtZSpD4vIKEcKRC;received=62.131.6.55
From: "Saúl" ;tag=9rNjdJVXH-y-5I8i1pzaTQ2lJnH83ktq
To: 
Call-ID: xvpzBMnseFltW2KzzbBAO4DX-ILHionW
CSeq: 15643 INVITE
Server: OpenSIPS (1.6.2-notls (x86_64/linux))
Content-Length: 0

--

2011-03-07 22:34:44.004037: RECEIVED: Packet 3, +0:00:00.210488
74.125.95.192:5060 -(SIP over UDP)-> 192.168.99.53:39101
SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.99.53:39101;received=62.131.6.55;rport=61928;branch=z9hG4bKPjuwdK-wRVFy7dsJD4xYtZSpD4vIKEcKRC
Record-Route: 
From: "Saúl" ;tag=9rNjdJVXH-y-5I8i1pzaTQ2lJnH83ktq
To: ;tag=1537395514
Call-ID: xvpzBMnseFltW2KzzbBAO4DX-ILHionW
CSeq: 15643 INVITE
Server: YATE/3.0.0
Contact: 
Allow: ACK, INVITE, BYE, CANCEL, REGISTER, REFER, OPTIONS, INFO
Content-Type: application/sdp
Content-Length: 183

v=0
o=yate 1299533672 1299533672 IN IP4 74.125.94.83
s=SIP Call
c=IN IP4 74.125.94.83
t=0 0
m=audio 65392 RTP/AVP 0 101
a=rtpmap:0 PCMU/8000
a=rtpmap:101 telephone-event/8000

--
2011-03-07 22:34:44.004432: SENDING: Packet 4, +0:00:00.210883
192.168.99.53:39101 -(SIP over UDP)-> 74.125.95.192:5060
ACK sip:+14049397606@10.13.154.2:7654 SIP/2.0
Via: SIP/2.0/UDP 192.168.99.53:39101;rport;branch=z9hG4bKPj8Cj2D-inZu80ylX.FAmnAxfo3-NkXkVv
Max-Forwards: 70
From: "Saúl" ;tag=9rNjdJVXH-y-5I8i1pzaTQ2lJnH83ktq
To: ;tag=1537395514
Call-ID: xvpzBMnseFltW2KzzbBAO4DX-ILHionW
CSeq: 15643 ACK
Route: 
User-Agent: sipsimple 0.17.1
Content-Length:  0

Nos ha contestado un YATE, interesante… ¿y si el usuario no existe?

INVITE sip:test@sip.voice.google.com SIP/2.0
Via: SIP/2.0/UDP 192.168.99.53:39101;rport;branch=z9hG4bKPjbIhDd.7vIzCwrZggWb1vRZ1KXCGSo2xw
Max-Forwards: 70
From: "Saúl" ;tag=o-QeubGVq.yh3Q-WN9yipgfWGOaexiPT
To: 
Contact: 
Call-ID: .O6U-GGy0TcQuD5fpM47wsiJXRiC0IN.
CSeq: 25827 INVITE
Allow: SUBSCRIBE, NOTIFY, PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, MESSAGE, REFER
Supported: 100rel, norefersub
User-Agent: sipsimple 0.17.1
Content-Type: application/sdp
Content-Length:   281

v=0
o=- 3508523286 3508523286 IN IP4 192.168.99.53
s=sipsimple 0.17.1
c=IN IP4 192.168.99.53
t=0 0
m=audio 50028 RTP/AVP 9 8 0 101
a=rtcp:50029
a=rtpmap:9 G722/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=sendrecv

--

2011-03-07 22:48:06.431428: RECEIVED: Packet 8, +0:13:22.637879
74.125.95.192:5060 -(SIP over UDP)-> 192.168.99.53:39101
SIP/2.0 404 Not Found
Via: SIP/2.0/UDP 192.168.99.53:39101;rport=64041;branch=z9hG4bKPjbIhDd.7vIzCwrZggWb1vRZ1KXCGSo2xw;received=62.131.6.55
From: "Saúl" ;tag=o-QeubGVq.yh3Q-WN9yipgfWGOaexiPT
To: ;tag=b6af3ec14a5583bc5e0a35f4053f902f.2904
Call-ID: .O6U-GGy0TcQuD5fpM47wsiJXRiC0IN.
CSeq: 25827 INVITE
Server: OpenSIPS (1.6.2-notls (x86_64/linux))
Content-Length: 0

--

2011-03-07 22:48:06.431510: SENDING: Packet 9, +0:13:22.637961
192.168.99.53:39101 -(SIP over UDP)-> 74.125.95.192:5060
ACK sip:test@sip.voice.google.com SIP/2.0
Via: SIP/2.0/UDP 192.168.99.53:39101;rport;branch=z9hG4bKPjbIhDd.7vIzCwrZggWb1vRZ1KXCGSo2xw
Max-Forwards: 70
From: "Saúl" ;tag=o-QeubGVq.yh3Q-WN9yipgfWGOaexiPT
To: ;tag=b6af3ec14a5583bc5e0a35f4053f902f.2904
Call-ID: .O6U-GGy0TcQuD5fpM47wsiJXRiC0IN.
CSeq: 25827 ACK
User-Agent: sipsimple 0.17.1
Content-Length:  0

Vuelve a contestarnos OpenSIPS. Por lo que parece OpenSIPS balancea la carga de YATE.

Voy a tentar la suerte y mandar un MESSAGE:

2011-03-07 22:51:44.024234: SENDING: Packet 13, +0:00:06.016478
192.168.99.53:46854 -(SIP over UDP)-> 74.125.95.192:5060
MESSAGE sip:+14049397606@sip.voice.google.com SIP/2.0
Via: SIP/2.0/UDP 192.168.99.53:46854;rport;branch=z9hG4bKPjp8qvrhlbAINZHmHSl1P9s9QlDZqtKsVG
Max-Forwards: 70
From: "Saúl" ;tag=3SMMO5vwdhW4LOXNXFcfy4dOfiAkOvzo
To: 
Call-ID: vcMiSLdsP56mxb5rIY6os94QuCWJ12V-
CSeq: 23424 MESSAGE
User-Agent: sipsimple 0.17.1
Content-Type: text/plain
Content-Length:     4

test
--

Could not deliver MESSAGE: 404 Not Found
2011-03-07 22:51:44.170734: RECEIVED: Packet 14, +0:00:06.162978
74.125.95.192:5060 -(SIP over UDP)-> 192.168.99.53:46854
SIP/2.0 404 Not Found
Via: SIP/2.0/UDP 192.168.99.53:46854;rport=64109;branch=z9hG4bKPjp8qvrhlbAINZHmHSl1P9s9QlDZqtKsVG;received=62.131.6.55
From: "Saúl" ;tag=3SMMO5vwdhW4LOXNXFcfy4dOfiAkOvzo
To: ;tag=b6af3ec14a5583bc5e0a35f4053f902f.7ee2
Call-ID: vcMiSLdsP56mxb5rIY6os94QuCWJ12V-
CSeq: 23424 MESSAGE
Server: OpenSIPS (1.6.2-notls (x86_64/linux))
Content-Length: 0

Una pena, esto hubiera sido para nota. Aunque lo extraño es que no rechaza el MESSAGE, dice que el usuario no existe.

Veremos con qué nos sorprende Google, espero que sea algo decente por lo que vender lo poco de alma que me pueda quedar 😉

NOTA: Si intentáis probar esto hoy ya no funcionará, no se si ayer funcionaba por un descuido o no, pero hoy lo han deshabilitado 🙁

Deteniendo un SIP flood con OpenSIPS y el módulo pike

Esta semana mientras miraba algo en uno de nuestros servidores me di cuenta de que estábamos siendo “atacados” mediante SIP flooding. Lo pongo entre comillas porque no era un ataque suficientemente significativo como para que el servicio se viera afectado, así que decidí aprovechar la ocasión para experimentar un poco y encontrar la manera de evitar éste tipo de ataques.

Como he dicho el ataque no era gran cosa: un montón de REGISTER que ni siquiera intentaban averiguar passwords. El problema de éste tipo de ataques es que pueden dejar nuestro sistema fuera de combate si los recursos no se liberan demasiado rápido. Los descriptores de fichero asignados a un proceso no son ilimitados (aunque ulimit -n diga lo contrario) y si se acaban no podremos hacer casi nada. Por otro lado, si la aplicación que está sufriendo el ataque consume el 100% de la CPU también estaremos afectando a otros procesos del sistema.

En estos casos un IDS como Snort puede ayudarnos, pero ya que se trata de OpenSIPS vamos a utilizar el módulo pike ya que viene incluido y así no necesitamos añadir un elemento más a nuestra infraestructura.

El módulo pike no bloquea el ataque de por si. Es capaz de detectarlo y de darnos las herramientas necesarias para actuar ente un ataque. Podéis ver toda la documentación del módulo, yo aquí comentaré los parámetros más relevantes:

  • sampling_time_unit: Indica el número de segundos que componen una muestra. A priori puede parecer algo abstracto, cobra sentido en combinación con el siguiente parámetro.
  • reqs_density_per_unit: Indica el número de mensajes permitidos en un sampling_time_unit, de manera que al sobrepasar éste número se ‘bloqueará’ la IP que esté originando el tráfico.
  • remove_latency: Indica el tiempo que tendremos una IP marcada como ‘bloqueada’.

Todas las unidades de tiempo se indican en segundos.

Una vez tenemos el módulo configurado vamos a utilizar la función pike_check_req() para detectar el flooding y actuar en consecuencia. Un ejemplo con un poco de pseudocódigo:

modparam("pike", "sampling_time_unit", 2)
modparam("pike", "reqs_density_per_unit", 30)
modparam("pike", "remove_latency", 120)
...
...
if (!(FROM_SELF || FROM_TRUSTED)) {
if (!pike_check_req()) {
exit;
}
}
...
...

Como se puede ver lo que haremos al detectar el flood es llamar a la función exit, para dejar de procesar los requests y liberar los recursos lo antes posible.

Alguno ya se habrá dado cuenta de que en realidad no estamos deteniendo el ataque… veamos como se podría hacer 🙂

El módulo pike nos generará unas bonitas entradas en syslog:

Jun 14 11:32:39 node03 /usr/sbin/opensips[12654]: PIKE - BLOCKing ip 1.2.3.4, node=0xaf793a68
Jun 14 14:15:43 node03 /usr/sbin/opensips[12659]: PIKE - UNBLOCKing node 0xaf793a68
Jun 14 14:15:45 node03 /usr/sbin/opensips[12623]: PIKE - BLOCKing ip 1.2.3.4, node=0xaf793axx
Jun 14 14:34:25 node03 /usr/sbin/opensips[12659]: PIKE - UNBLOCKing node 0xaf793axx
Jun 14 14:34:27 node03 /usr/sbin/opensips[12646]: PIKE - BLOCKing ip 1.2.3.4, node=0xaf793axx
Jun 14 15:35:39 node03 /usr/sbin/opensips[12659]: PIKE - UNBLOCKing node 0xaf793axx

Todo lo que tendremos que hacer es detectar estos mensajes con Rsyslog (por ejemplo) y añadir temporalmente una regla de iptables para bloquear el tráfico.

Ala, ya tenéis deberes 😉

4005407576_a1e671452d_m

ICE: The ultimate way of beating NAT in SIP

Hoy ha sido el día. A las 15:00 he tenido la oportunidad de dar una charla en el Amoocon 2010. La charla trataba sobre cómo ‘atravesar’ el NAT utilizando ICE, algo de lo que ya hablamos hace algunos posts.

A continuación os dejo las transparencias, que espero sirvan a alguien para aclarar el concepto de ICE en si, y cómo lo hicimos funcionar correctamente con OpenSIPS y MediaProxy.


Njoy! 🙂

“Atravesando” el NAT con OpenSIPS 1.6 y MediaProxy

Hoy vamos a ver como configurar OpenSIPS 1.6 y MediaProxy para solucionar los problemas que el NAT nos pueda traer.

Configurar el proxy para solucionar los problemas de NAT suele ser de las primeras cosas que se pretende o se hace al configurarlo, pero en muchas ocasiones se olvida el primer paso: entender el NAT. En su día escribí un post con una breve introducción al NAT, pero lo que os recomiendo es que os leáis varias veces éste post de Iñaki Baz Castillo explicando como afecta el NAT al protocolo SIP así así como los distintos tipos de soluciones.

En este post vamos a ver como “arreglar” el NAT con OpenSIPS 1.6 y MediaProxy. El módulo mediaproxy de OpenSIPS nos servirá en combinación con el propio MediaProxy para arreglar el SDP y hacer que el RTP pase por MediaProxy, mientras que para arreglar la parte de señalización utilizaremos el módulo nat_traversal.

El módulo nat_traversal

Este módulos nos servirá para arreglar la cabecera Contact de los mensajes SIP nateados y mantener el NAT abierto haciendo keepalive del lado servidor. El módulo nat_traversal tiene una particularidad que le diferencia de otros módulos similares: fue diseñado para tratar entornos multi-proxy, como por ejemplo el caso en que el proxy que mantiene el keepalive no sea el que gestiona los REGISTER (el registrar). No vamos a entrar en detalle en este post, pero conviene tenerlo en cuenta…

El módulo mediaproxy

Este módulo gestiona la comunicación con el servidor MediaProxy, de manera que el módulo modificara el SDP para que el audio pase por MediaProxy, que actuara de media relay. Como comente en un post anterior MediaProxy soporta ICE, por lo que podremos arreglar el NAT en prácticamente todos los casos (salvo los malditos ALGs).

Antes de empezar

Antes de comenzar la descripción de la configuración necesaria es importante comentar que en este post vamos a utilizar el método fácil. El módulo mediaproxy tiene 2 formas de funcionar:

  1. Funciones use_media_proxy y end_media_session: han de ser llamadas por el usuario, por lo tanto este ha de saber exactamente cuando quiere que MediaProxy comience o acabe su funcionamiento. Grosso modo tendremos que encargarnos del primer INVITE, los in-dialog-requests y el BYE. Lo veremos en otro post 😉
  2. Función engage_media_proxy: utiliza el módulo dialog para llamar a las funciones del punto 1 internamente. El usuario solo tiene que llamar a la función engage_media_proxy en el primer INVITE y olvidarse, el resto se realizara internamente. El hecho de que sea tan fácil también trae algunas limitaciones, que veremos mas adelante.

Arreglando la señalización

Primero vamos a configurar el módulo nat_traversal, con el que podremos arreglar el NAT en la señalización.

loadmodule "nat_traversal.so"
...
modparam("nat_traversal", "keepalive_interval", 60)
modparam("nat_traversal", "keepalive_method", "OPTIONS")
modparam("nat_traversal", "keepalive_extra_headers", "X-Keepalive: yes\r\n")
modparam("nat_traversal", "keepalive_state_file", "/var/run/opensips/keepalive_state")

Con los parámetros indicados haremos que el módulo nat_traversal mande un mensaje SIP OPTIONS cada 60 segundos para mantener el NAT abierto. Ademas, añadiremos la cabecera X-Keepalive, simplemente para identificar estos paquetes mejor.

Para hacer que el módulo comience a enviar los OPTIONS será necesario que llamemos a la función nat_keepalive(). La particularidad de esta función es que no provoca que el mecanismo comience de inmediato, sino que será activado en caso de recibir/generar una respuesta positiva a un REGISTER o SUBSCRIBE y cuando un dialogo comience con un INVITE.

...
if ((method=="REGISTER" || method=="SUBSCRIBE" ||
(method=="INVITE" && !has_totag())) && client_nat_test("3"))
{
nat_keepalive();
}
...

Ademas del keepalive, también tendremos que modificar los mensajes SIP para que la cabecera Contact contenga la IP y puerto reales desde los que vino el paquete en lugar de lo que el terminal del usuario haya puesto. También añadiremos el parámetro rport a la cabecera Via, de manera que OpenSIPS anyadira la IP y el puerto desde los que recibió el paquete a la primera cabecera Via aunque el terminal no indicara soporte para rport. Para ello incluiremos lo siguiente en nuestro request route:

if (client_nat_test("3")) {
force_rport();
fix_contact();
}

Es posible que las respuestas también vengan nateadas, porque el terminal al que llamamos esta detrás de NAT así que tenemos que tratarlas en un onreply route:

if (client_nat_test("1")) {
fix_contact();
}

Ya solo nos queda una cosa para terminar con la señalización: fijar el AVP necesario para que OpenSIPS guarde la dirección IP y puerto desde la que se ha registrado el usuario en la tabla location de su base de datos:

modparam("registrar", "received_avp", "$avp(s:received_uri)")
...
$avp(s:received_uri) = $source_uri;

La pseudovariable $source_uri es exportada por el módulo nat_traversal y contiene la IP, puerto y transporte desde los que se recibió el paquete.

Arreglando el RTP

Una vez tenemos la señalización arreglada necesitamos hacer que el RTP pase por nuestro servidor MediaProxy. Para ello modificaremos el SDP de manera que la IP y puerto desde los que se supuestamente se enviara el RTP sean realmente el servidor de MediaProxy.

Como hemos comentado anteriormente vamos a utilizar el método fácil, por lo que solo tendremos que llamar a la función engage_media_proxy() para el primer invite:

if (is_method("INVITE") && !has_totag()) {
engage_media_proxy();
}

Limitaciones

Todo no puede ser perfecto, por lo que el método que aquí hemos utilizado puede no ser el mejor para todos los casos. En concreto estas son las limitaciones que el sistema utilizado conlleva:

  • Se utilizara siempre MediaProxy: dado que la función engage_media_proxy() utiliza el módulo dialog para funcionar es necesario llamarla al comienzo del dialogo, así que llamarla al recibir un 200 OK nateado seria demasiado tarde.
  • Manejo de múltiples diálogos: tanto OpenSIPS como MediaProxy sufren al recibir múltiples respuestas con SDP a un INVITE (dos 183 por ejemplo), por lo que los resultados son inesperados.

Dado que la mayoría de usuarios están detrás de NAT y que gracias a la arquitectura escalable de MediaProxy podemos ampliar los recursos a medida que los vayamos necesitando, tendremos que valorar la facilidad en la configuración frente a la flexibilidad en la gestión de NAT.

Happy NAT traversing!

Building Telephony Systems with OpenSIPS 1.6

Hoy os voy a comentar la impresión que me he llevado tras leer el libro “Building Telephony Systems with OpenSIPS 1.6” de Flavio E. Goncalves. Si Manwe si, ya se que para ti esto no cuenta como libro pero bueno. 😉

Al igual que la versión anterior (Building Telephony Systems with OpenSER) la idea del libro es introducir al lector en la configuración de OpenSIPS e ir avanzando poco a poco e ir integrando más servicios.

Aunque saber algo SIP es más que recomendable, el libro comienza con una introducción a SIP, y a lo largo de los capítulos se muestran capturas con ngrep, para poder entender como afecta la configuración de OpenSIPS a los mensajes SIP y su procesamiento.

La estructura es muy acertada, ya que se comienza con una configuración muy básica sin tan siquiera autenticación, para terminar con una configuración que incluye autenticación en MySQL, tratamiento de NAT, accounting en RADIUS, …

  • Capítulo 1: Introduction to SIP: Una breve introducción a SIP, SDP y RTP para conocer los aspectos básicos de los protocolos involucrados.
  • Capítulo 2: Introduction to OpenSIPS: Introducción a las características de OpenSIPS  y la estructura del fichero de configuración.
  • Capítulo 3: OpenSIPS installation: Detalle de la instalación de OpenSIPS en una Debian compilando OpenSIPS desde los ficheros fuente.
  • Capítulo 4: Script and routing basics: Configuración básica de OpenSIPS (sin auntenticación ni nada) y explicación más detallada de la estructura del fichero de configuración.
  • Capítulo 5: Adding authentication with MySQL: Partiendo de la configuración del capítulo 4 se añade autenticación de usuarios utilizando MySQL como backend.
  • Capítulo 6: Graphical user interfaces for OpenSIPS: Éste capítulo me ha parecido bastante interesante, ya que se exponen las 2 GUIs que actualmente hay para OpenSIPS: serMyAdmin y OpenSIPS-CP (que acaban de estrenar versión), y teniendo en cuenta que a muchos les tira para atrás el hecho de no poder administra el proxy con algo gráfico… Aunque el verdadero poder siempre estará en la consola 😉
  • Capítulo 7: Connectivity to PSTN: Configuraciones para la interconexión de OpenSIPS con la PSTN. Routing dinámico, grupos de usuarios, permisos, …
  • Capítulo 8: Media Services integration: Integración de OpenSIPS (recordemos que es un proxy, no entiende de audio) con servidores de media como Asterisk, con ejemplos de configuración e integración con Asterisk en RealTime.
  • Capítulo 9: SIP NAT traversal: El capítulo que todos los recién llegados a OpenSIPS querrán leer. 🙂 Explicación de cómo “arreglar” el NAT con RTPProxy. A ver si para la próxima edición se puede incluir también MediaProxy 😉
  • Capítulo 10: Accounting and billing: Configuración de OpenSIPS para hacer accounting en MySQL y FreeRADIUS.
  • Capítulo 11: Monitoring tools: Explicación de algunas herramientas de configuración y diagnóstico como sipsak o SIPp.

He resumido mucho, así que os recomiendo que si queréis empezar a aprender OpenSIPS os lo compréis (no es caro) y lo pongáis en vuestra mesita de noche, justo al lado del RFC3261. 😉

643cc7cfopengfx