SIP Behind NAT: Engañar al NAT con más NAT

Alejop!

La verdad es que llevábamos bastante tiempo sin escribir desde el dpto de voz ip de Irontec, y en esta ocasión no es que hayamos preparado un súper post,  pero esto nos ha parecido lo suficientemente trickie como para comentarlo por aquí, sobre todo por la vuelta de tuerca y lo divertida que es la solución, al menos para nosotr@s 😉

No es que sea magia negra, realmente son dos comandos, pero nos ha gustado como para compartirlo por aquí 😉 Sobre todo porque no lo hemos visto comentado por la comunidad.

Del NAT en SIP se ha hablado largo y tendido en todos lados, incluso por aquí hemos comentado algo, creo que cualquier ingeniero de voz ip la primera vez que habla con el ingeniero de redes del cliente que le toca en el proyecto acaba usando los mismos ejemplos «que si viajan IP’s dentro» «que si se parece al protocolo FTP antes del passive mode» o para los vintages «si, es como el DCC del IRC», así que sobran presentaciones.

La razón de la aventura / objetivo

Hoy por hoy, el que no está lanzando containers, está al menos en algún cloud, o suyo o de big player, y los big players lo que no hacen nunca es darte la IP Pública, te la redirigen, te permiten que sea estática o no, te dejan jugar con balanceadores, o te permiten unir todo como si fueran piezas de Lego sin pensar en lo que hay abajo.

Es para ese caso concreto al que nos referimos.

Si bien es cierto que a nivel de signalling las aplicaciones mas conocidas del lado open source en la parte SIP lo soportan bien:

No siempre es algo que nos guste o que se adapte a todos los casos. El mero hecho de tener ya un binding a una IP privada nos puede generar problemas… por ejemplo:

  • si tenemos Kamailio y un entorno híbrido de b2bua’s/otros proxy’s también en la misma vtnet del hoster/provider de cloud.
  • o si queremos tener binding a varias IPs por las razones que sea (multi servicio / migración / X – que acabamos aquí).
  • o si el concepto en Asterisk/FreeSwitch/Kam de «localnet» no es siempre fijo y queremos que dependa mas bien de una red gestionada por software / devops style en función de dónde estemos naciendo (muy alineado con el escalado automático o soluciones tipo IVOZ Provider que pueden ser diseñadas para ello).

En estos casos, siempre se acaba haciendo una travesía de peregrinaje por el desierto del Gobi , odiando más el nat y con peleas eternas de record-route vs via / peleas varias con el domain del contact y resto de pesadillas (que también hay que decir que no suceden si tenemos algo simple y standard tras NAT).

Vamos, que siempre te acabas acordando de lo bonito que es estar con un binding a una pública directa y llanamente.

NO es que sea algo que pase realmente mucho, de hecho tienes que estar en muchas batallas para que estadísticamente te toque usar este arma ninja XDD

Viéndolo gráficamente

Tal cual, nada del otro mundo, lo más  habitual que no merece casi ni explicarse:

 

El veneno que engaña/mata el NAT: Más NAT [!]

Digamos que empezamos así:

«Me da  igual lo que digas, yo empiezo con un listen=37.37.37.37:5060 porque quiero escuchar en la pública y que el proceso X lo sepa y fin, que si no es un lío»

Pues muy bien 🙂 GoGoGo! Hay veces que hay empezar al revés para enfocar el túnel 😉

Para empezar, a menos que tengas la setting de NON LOCAL Bind (bastante usado en HA para evitar restarting de resources) no vas a poder hacerlo, así que let’s do it!, aunque no sepamos todavía hacia dónde vamos:

echo 1 > /proc/sys/net/ipv4/ip_nonlocal_bind

Con esto ya esta, ya podemos escuchar en IP’s que ni tenemos en nuestras tarjetas y… fin.

Aunque realmente para esta prueba funciona con:

ip addr add 37.37.37.37/32 dev eth0

Si, peroooo, ¿ya estamos?

¿Qué pasa con el tráfico entrante?

El tráfico entrante, pasa por el proveedor del cloud, que hace el DNAT(Port Forward/como quieras llamarlo) para meterlo, el paquete tiene como destino la IP privada de la vnic del host, así que a engañarle:

iptables -t nat -I PREROUTING -d 192.168.1.100 -p udp --dport 5060 -j DNAT --to 37.37.37.37

 

Y tachán, lo que entra por la vnic con destino la privada se transforma en destino para que sea la pública y como estamos bindeados a ella, la vida es bella y fin de la cita 😉

¿Qué pasa con el tráfico saliente?

El proceso que tenemos está haciendo binding en una IP que no será aceptada en salida por el router del cloud. Si nos presentamos con dicha IP nos va a sacar el dedo, y desde luego no lo va a enrutar, así que engañémosle:

iptables -t nat -I POSTROUTING -s 37.37.37.37 -p udp --sport 5060 -j SNAT --to 192.168.1.100

Voilà! Con esto tenemos a un proceso que piensa que está enviando tráfico con una IP pública como origen y realmente está saliendo con su privada, que luego el router frontera lo cambiará de nuevo.

¿Y este WTF funciona de verdad?

Jiji, si, en este caso para probarlo hemos creado en LightSail de Amazon una micro instancia tal que:

Es decir, una VM con la IP Pública asignada 35.176.149.215

Como IP de LAN:

root@ip-172-26-14-149:~# ip a s dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 06:9d:21:64:33:e9 brd ff:ff:ff:ff:ff:ff
    inet 172.26.14.149/20 brd 172.26.15.255 scope global eth0

Hemos optado por probar con Asterisk 15 mismamente, ya que el gran Elio ya nos lo iba avanzando 😉  Pero lo dicho, esta técnica vale para cualquier soft que se ejecute en GNU/Linux (SEMS, Kamailio, Freeswitch, OpenSIPS, Asterisk, SIPP, Blackbox SIP, ….).

Nada del otro mundo, el binding:

root@ip-172-26-14-149:~# grep udpbindaddr /etc/asterisk/sip.conf 
udpbindaddr=35.176.149.215

Que validamos:

root@ip-172-26-14-149:~# netstat -ulnp | grep 5060
udp        0      0 35.176.149.215:5060     0.0.0.0:*                           15419/asterisk

Es decir, estamos escuchando en una IP que no es nuestra, activamos el NAT:

root@ip-172-26-14-149:~# iptables -t nat -A POSTROUTING -o eth0 -s 35.176.149.215 -p udp -j SNAT --to 172.26.14.149
root@ip-172-26-14-149:~# iptables -t nat -I PREROUTING -i eth0 -d 172.26.14.149 -p udp -j DNAT --to 35.176.149.215

Y basta con ver esas flechas tan bonitas que nos muestra SNGREP (en este caso un SIP OPTIONS contra un ITSP conocido):

Cuando realmente, en modo debug:

Really destroying SIP dialog '[email protected]:5060' Method: OPTIONS
Reliably Transmitting (no NAT) to 194.30.A.B:5060:
OPTIONS sip:194.30.A.B SIP/2.0
Via: SIP/2.0/UDP 35.176.149.215:5060;branch=z9hG4bK13470560
Max-Forwards: 70
From: "asterisk" <sip:[email protected]>;tag=as4ee6b87d
To: <sip:194.30.A.B>
Contact: <sip:[email protected]:5060>
Call-ID: [email protected]:5060
CSeq: 102 OPTIONS
User-Agent: Asterisk PBX 15.0.0-rc1
Date: Wed, 06 Sep 2017 17:52:15 GMT
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH, MESSAGE
Supported: replaces, timer
Content-Length: 0

Es realmente como si hubiéramos configurado el externip/localnet, o realmente como si estuviéramos con la pública (que realmente lo estamos a nivel de binding).

Por concluir

Puede que parezca un poco trickie, pero de verdad que es un arma especialista que en algunas batallas de net complejas o de situaciones temporales de migraciones dónde estas redirigiendo tráfico o similares, viene muy bien 😉

Acordaros igualmente de los puertos de audio para el RTP :=)

Esperamos tener pronto algo no tan «specific» que comentaros desde aquí 😉

¡Hasta otra!

 

 



¿Te gusta este post? Es solo un ejemplo de cómo podemos ayudar a tu empresa...
Sobre Gorka Gorrotxategi

CTO en Irontec, en el frente técnico desde un par de lustros ya, para todo lo que tenga que ver con Networking, VoIP y Sistemas, en ese orden :D) Desde @zetagor escribo algo, pero poco verbose la verdad

Queremos tu opinión :)