Tráfico RTP directo entre dispositivos con NAT (y parche)

En asterisk, el parámetro “canreinvite=yes” en sip.conf a la hora de definir un dispositivo SIP, indica la disponibilidad de dicho dispositivo a aceptar tráfico RTP directamente desde el otro dispositivo involucrado en la llamada, sin que asterisk tenga que estar en medio de la comunicación, reenviando la información de uno a otro.

En una red local, no hay gran problema… cualquier red que se precie usa cable CAT5 y switches 10/100… más que de sobra como para que afecte ese extra de paquetes circulando. Sin embargo, cuando tenemos un asterisk en una sede, y varios teléfonos SIP en otra sede distinta (conectados mediante ADSL, por ejemplo), la cosa cambia.

El ancho de banda de una ADSL es asimétrico, y aunque tengamos 3 “megas” de bajada, la subida no suele pasar de unos míseros 320kbs (bits, no bytes). De ahi que sea un recurso muy valioso, como para malgastarlo cuando no es realmente necesario. Con este ancho de banda, podemos mantener unas 10 conversaciones con el códec G729, y unas 3 con G711. (Usando esta calculadora de ancho de banda)

Un caso típico

Imaginemos el siguiente escenario:

  • Un servidor asterisk en la sede central
  • Teléfonos SIP en la sede A (A1,A2,A3..An). Todos ellos configurados con nat=yes.
  • Otros tantos en la sede B (B1..Bn).También con nat=yes.
  • En ninguna de las dos sedes se abren puertos hacia los diferentes teléfonos.

diagrama.PNG

Si impedimos el tráfico de paquetes de voz (RTP) directo entre teléfonos (canreinvite=no), al hacer una llamada interna, desde A1 a A2, habría dos flujos de paquetes:

  1. Desde A1 hasta el servidor asterisk, y desde aquí de vuelta a A2
  2. Justo el camino contrario, ya que la comunicación es full-duplex.

Fíjemonos que para una simple conversación entre extensiones, estamos utilizando nuestra conexión ADSL por partida doble. Estamos utilizando 2 de las llamadas simultáneas disponibles con nuestra humilde conexión a internet.

En una llamada desde A1 a B1 pasaría lo mismo, salvo que en este caso es lo que esperamos. A1 y B1 están en sedes distintas, y no hay forma de que se pueda establecer una comunicación directa entre ambos dispositivos. Lo que queremos es que asterisk haga de enlace entre ambos. Cada sede estará gastando un canal de los que tenga disponible.

Queremos evitar este consumo innecesario de ancho de banda cuando los dos teléfonos pueden establecer una comunicación RTP directa. Para ello, activaremos “canreinvite=yes” en la configuración de todos los dispositivos. Repetimos el experimento.

Llamamos desde A1 a A2. Asterisk, que hace de intermediario, indica a A1 que envíe su tráfico RTP a la dirección de A2, y hace lo propio con A2. Las direcciones IP utilizadas son las IP’s locales de cada teléfono (192.168.0.x, por ejemplo), y no la IP pública de la ADSL de la sede.

El beneficio es palpable, mientras asterisk se encarga de la señalización (indicando cuando un teléfono cuelga, cuando se hace una transferencia, etc), el tráfico RTP de voz va directamente de un teléfono a otro, sin salir a Internet en ningún momento, y sin gastar ningún canal.

Pero todo tiene un “pero”. Al hacer una llamada desde A1 a B1, asterisk también indicará a los dispositivos que se envíen el tráfico RTP directamente entre ellos. El problema está en que, al utilizar las IP’s privadas y ser dos redes distintas, separadas, que podrían incluso compartir la misma dirección de red, la llamada se establecerá pero no habrá audio en ningún sentido. Mal asunto.

¿Por qué? En la actualidad, cuando ambos dispositivos están configurados con “canreinvite=yes”, asterisk obedece y siempre que puede intenta que se envíen el tráfico RTP entre ellos directamente. Lamentablemente, cuando están en redes distintas, es imposible. La solución estaría en comprobar, cuando los dispositivos están detrás de routers haciendo NAT, si la dirección IP pública de ambos coincide. Si fuese el caso, podremos estar seguros de que están en la misma red, y podrán encontrarse. Si la IP pública es diferente, asterisk simplemente debe quedarse en medio.

Las llamadas dentro de cada sede funcionarán bien, sin malgastar ancho de banda de la ADSL, mientras que las llamadas entre sedes pasaran a través de asterisk.

Una solución

Y después de esta soberana paliza (que no se cuántos habréis aguantado), os dejo aquí el parche para la revisión r79171 del svn de asterisk/branches/1.4.

Descargar asterisk_nat_rtp_recv_patch_v3.diff

Para aplicar

$ cd /usr/src/asterisk
$ patch -p0 < /ruta/a/asterisk_nat_rtp_recv_patch_v3.diff
$ make
$ make install

Añadimos natonlyreinvitesameip=yes a la sección [general] de nuestro sip.conf.

No he podido testear a fondo este parche, así que si alguien puede reproducir este escenario, agradecería comentarios sobre si funciona o si es una soberana estupidez ;)

Escrito por julianjm el 12/08/2007. | Comments (16)
Tags: , , ,