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.com -> juan@b.com - Ahora imaginemos que luis@a.com llama a pepe@a.com por lo que también llamaría (o intentaría llamar) a juan@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@b.com ya que el llamante se había autenticado **pero para llamar a alguien de su dominio, a pepe@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.