Hola, después de pelearme unos cuantos días creo que ya tengo suficientemente
bien implementado el tema del forwarding, es decir, que al llamar a un
usuario se consulte si tiene otra URI asociada y se le llame a ambas en
paralelo hasta que coja de una de ellas.
Lo primero me gustaría comentar que lo que en muchos sitios se explica
como "forwarding" al mero hecho de poner un "append_branch()" me
parece
bastante incierto, hay que tener mucho cuidado ya que el nuevo branch no debe
pasar de nuevo por un auth (o fallará en el lado cliente). Es decir, si
alguien llama al "pepe" y se crea un nuevo branch a "juan", el nuevo
branch
que va a "pepe" consiste en un nuevo INVITE originado por OpenSer que pasaría
de nuevo por el authenticate y demás (salvo que se añadan cabeceras para
evitarlo o se testee la IP de origen y tal). Si no se tiene cuidado se
volverá a pedir autenticación sobre ese INVITE para el cuál ya se había
autenticado el usuario que llama y cuyo cliente fallará si recibe
otro "authenticate" (lo he comprobado).
Bueno, y para complicarlo un poco más yo lo tengo puesto en modo multidominio,
con restricciones de llamadas entre dominios (cada dominio decide quién puede
llamar a qué miembros del dominio) y además permito forwarding a dominios
distintos del local (estos dominios podrían ser a la vez locales o externos,
pero debe implicar el mismo comportamiento pues pretendo independencia total
de dominios).
Después de probar unas cuantas cosas he optado por hacer un "outbound" tal
cuál al INVITE cuya URI se ha modificado con la del forwarding, sea el nuevo
dominio el mismo u otro diferente (local o externo), por eso creo que
un "outbound" es lo más sencillo: si el dominio es local ya volverá el
paquete XD
Después de la chapa comento mi trocito de INVITE y el forwarding:
# -----------------------------------------------------------------
# INVITE
# -----------------------------------------------------------------
route[3] {
# Comprobamos los aliases. Recordar que los alias son sólo del mismo dominio.
route(10); # Aliases.
# Permisos.
if (!route(4)) { # Trusted.
# Sólo pedimos autenticación si es el llamante es local.
if (is_from_local()) {
route(6); # Auth.
}
route(7); # Grupos.
# Comprobamos los permisos ACL entre-dominios.
route(5); # ACL.
}
# Comprobamos los forwardings. Pueden apuntar a otros dominios.
route(11); # Forwarding.
# Ahora buscamos el usuario llamado.
route(12); # Location.
}
Y el forwarding:
# -----------------------------------------------------------------
# Forwarding
# -----------------------------------------------------------------
route[11] {
if ($hdr(Forwarding)) {
xlog("L_INFO", "Encontrada cabecera 'Forwarding' -> No miramos
tabla 'forwarding' para $ru\n");
return(-1);
}
avp_db_query("SELECT uri FROM forwarding WHERE
username='$rU'", "$avp(s:forwarding_uri)");
if ($rc == 1) {
# Cabecera para que el nuevo branch y el actual (via outbound)
# no pasen por "trusted":
append_hf("No-Trusted: Forwarding\r\n");
# Cabecera para que el nuevo branch no vuelva a pasar por "forwarding":
append_hf("Forwarding: Yes\r\n");
# Cabecera para que el nuevo branch y el actual (via outbound)
# no se tengan que volver a autenticar en "auth".
append_hf("Authenticated: Yes\r\n");
append_branch();
$ru = $avp(s:forwarding_uri);
remove_hf("Forwarding"); # En el INVITE original modificado a la URI del
forwarding quitamos esta cabecera pues la URI del forwarding podría contener
a su vez otro forwarding.
# Enviamos el INVITE modificado con la URI del forwarding a outbound.
# Si tiene que volver ya volverá.
route(9); # Outbound.
exit;
}
}
En fin, ¿es correcto? Me funciona bien y por ejemplo tiene en cuenta el
siguiente caso un poco "tramposo":
- Imaginemos dos dominios locales "a.com" y "b.com".
- b.com tiene puestos unos ACLs que impiden llamadas entrantes desde a.com.
- Un espavilado de a.com define un forwarding: pepe(a)a.com -> juan(a)b.com
- Ahora imaginemos que luis(a)a.com llama a pepe(a)a.com por lo que también
llamaría (o intentaría llamar) a juan(a)b.com.
- Si yo no hiciese el outbound final en el forwarding, o bien añado mucha
lógica redundante sobre permisos, o mi OpenSer cometería el error de permitir
la llamada a juan(a)b.com ya que el llamante se había autenticado **pero para
llamar a alguien de su dominio, a pepe(a)a.com**.
- Por eso yo he optado por hacer un outbound, así la llamada vuelve a entrar,
con la cabecera añadida y comprobando que viene de la IP de OpenSer evito que
vuelva a tener que autenticarse, pero el INVITE pasa por el ACL's donde se le
deniega la llamada al dominio b.com.
Pues eso, ¿qué os parece así? ¿estoy olvidando algo?
Gracias por cualquier opinión y sugerencia. Saludos.
--
Iñaki Baz Castillo