Bienvenidos a una nueva entrada en nuestro blog empresarial, esperamos que este articulo sea de ayuda.
En esta ocasión nos alejaremos momentáneamente de la linea regular y nos centraremos en el segmento de la video vigilancia, particularmente con la marca Dahua.
Por lo general el adquirir una cámara para nuestro uso personal no representa mayor problema, sin embargo cuando necesitamos algunas configuraciones particulares la situación cambia y es que en este caso se requiere que una o varias cámaras dahua se puedan consumir a través de un proxy reverso que trabaja con apache.
En primera instancia la configuración parecería sencilla, ya que solo sería definir unas entradas de proxypass y ya quedaría. Pero no, dahua no nos lo coloca sencillo y es que la forma en que esta construido el servidor web de la cámara es complejo, las rutas están cargadas dentro de archivos javascript, mismos que son llamados por scripts previamente cargados, lo que anula la funcionalidad del proxy reverso.
Por lo tanto de las pocas salidas practicas viables fue el usar un modulo de apache para sobre-escribir estas rutas de los archivos .js tarea que en un inicio pensamos delegar al modulo mod_substitute, pero rápidamente nos dimos cuenta que las tareas de sustitución son limitadas a una sola expresión regular, por lo tanto necesitamos un modulo mas robusto y en este punto fue donde nos encontramos con este fantástico proyecto de Gilles Darold, mismo a quien damos todo el crédito posible y enlazamos para su consulta y apoyo.
https://github.com/darold/modproxyperlhtml
Este modulo por decirlo de alguna forma nos permite realizar múltiples sustituciones sobre el contenido, lo cual resuelve en gran medida la problemática inicial. Su funcionamiento detallado lo pueden consultar en el enlace previo.
Una vez realizadas las sustituciones en tiempo real del contenido de las urls, nos encontramos con el detalle de los websocket, esto sería un detalle menor si no fuese porque la cámara transmite su video a través de websockets.
Esta limitante la resolvimos con el modulo mod_rewrite. Dicho lo anterior vamos a ver el ejemplo completo y a realizar los pequeños comentarios.
#Iniciamos con la definición de una variable la cual usaremos para trabajar sobre un subdirectorio de la url. Aquí asumimos que tendremos varias cámaras sobre el mismo virtualhost, accediendo de la siguiente forma: http://ip_o_dominio/cam1
Define path_cam1 cam1
#Seguidamente definimos un directorio sobre el cual haremos la definición del proxy reverso.
<Location /${path_cam1}>
#Activamos el modulo RewriteEngine, este nos permitirá capturar la solicitud del websocket y dirigirla adecuadamente, esto es fundamental para el stream de video.
RewriteEngine On
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/?(.*) “ws://192.168.5.253/$1” [P,L]
#Definimos el proxy reverso
ProxyPass http://192.168.5.253
ProxyPassReverse http://192.168.5.253
#Activamos el modulo ModProxyPerlHtml, para hacer uso de este es mandatorio instalarlo previamente según instrucciones de su sitio en github.
PerlInputFilterHandler Apache2::ModProxyPerlHtml
PerlOutputFilterHandler Apache2::ModProxyPerlHtml
SetHandler perl-script
# Definición de las expresiones regulares, mismas que se encargarán de modificar el contenido para que sea posible acceder a la camara a través del proxy inverso.
PerlAddVar ProxyHTMLRewrite “src\=(\”)(jsBase|jsCore|js)(\/) src\=$1${path_cam1}$3$2$3″
PerlAddVar ProxyHTMLRewrite “(\”)(\/)(OutsideCmd)\” $1$2${path_cam1}$2$3$1″
PerlAddVar ProxyHTMLRewrite “(\/web_caps\/) \/${path_cam1}$1”
PerlAddVar ProxyHTMLRewrite “(splayerCore\/SPlayer) ${path_cam1}\/$1”
PerlAddVar ProxyHTMLRewrite “(\”\/jsBase\/lib) \”\/${path_cam1}\/jsBase\/lib”
PerlAddVar ProxyHTMLRewrite “(\’)(\.)(\/)(jsBase)(\’) $1$2$3${path_cam1}/$4$1”
PerlAddVar ProxyHTMLRewrite “(\’)(\.)(\.)(\/)(js)(\’) $1$2$3$4${path_cam1}$4$5$1”
PerlAddVar ProxyHTMLRewrite “(\’)(\.)(\.)(\/)(html)(\’) $1$2$3$4${path_cam1}$4$5$1”
PerlAddVar ProxyHTMLRewrite “(\’)(\.)(\.)(\/)(platformHtm)(\’) $1$2$3$4${path_cam1}$4$5$1”
PerlAddVar ProxyHTMLRewrite “(\’\/jsCore\/app’) \’\/${path_cam1}\/jsCore\/app\'”
PerlAddVar ProxyHTMLRewrite “(\’css\/) \’${path_cam1}\/css\/”
PerlAddVar ProxyHTMLRewrite “(\’css_FS\/’) \’${path_cam1}\/css_FS\/'”
PerlAddVar ProxyHTMLRewrite “(\’jsBase\/) \’${path_cam1}\/jsBase\/”
PerlAddVar ProxyHTMLRewrite “(\/current_config\/) \/${path_cam1}$1”
PerlAddVar ProxyHTMLRewrite “(\/default_lang\/) \/${path_cam1}$1”
PerlAddVar ProxyHTMLRewrite “(\/custom_lang\/) \/${path_cam1}$1”
PerlAddVar ProxyHTMLRewrite “(\”splayerCore\/splayerAdapter.js\”) \”${path_cam1}\/splayerCore\/splayerAdapter.js\””
PerlAddVar ProxyHTMLRewrite “(\”)(js\/index\.js) $1\.\.\/$2″
PerlAddVar ProxyHTMLRewrite “(m|p)(\=\”)(js|html)(\/)(\”) $1$2\.\.$4$3$4$5″
PerlAddVar ProxyHTMLRewrite “(\”)(\/)(html)(\/\”)(\+b\.) $1$2${path_cam1}$2$3$4$5″
PerlAddVar ProxyHTMLRewrite “(\”)(\/)(jsCore\/pageBase)(\”) $1$2${path_cam1}\/$3$1″
PerlAddVar ProxyHTMLRewrite “(\”)(\/)(jsCore\/ability)(\”) $1$2${path_cam1}\/$3$1″
PerlAddVar ProxyHTMLRewrite “(\”)(\/)(jsCore\/rpc)(\”) $1$2${path_cam1}\/$3$1″
PerlAddVar ProxyHTMLRewrite “(\”)(\/)(jsCore\/rpcLogin)(\”) $1$2${path_cam1}\/$3$1″
PerlAddVar ProxyHTMLRewrite “(\”)(\/)(jsCore\/mTokenOperator)(\”) $1$2${path_cam1}\/$3$1″
PerlAddVar ProxyHTMLRewrite “(\”)(\/)(jsCore\/h5player)(\”) $1$2${path_cam1}\/$3$1″
PerlAddVar ProxyHTMLRewrite “(\”)(\/)(jsCore\/plugin)(\”) $1$2${path_cam1}\/$3$1″
PerlAddVar ProxyHTMLRewrite “(e\=\[)(\”)(\/)(js)(\/\”) $1$2$3${path_cam1}$3$4$5″
PerlAddVar ProxyHTMLRewrite “(\”)(module)(\/)(audioWorker|videoWorker)(\.js\”) $1${path_cam1}$3$2$3$4$5″
PerlAddVar ProxyHTMLRewrite “(\”)(\/)(module)(\/)(public|Sylvester|mp4remux|WebGLCanvas|audioPlayer|streamDrawer|videoMediaSource|workerManager|WebsocketServer|playerControl|ivs)(\”) $1$2${path_cam1}$2$3$4$5$1″
PerlAddVar ProxyHTMLRewrite “(\”)(\/)(RPC2\_Login|RPC2)(\”) $1$2${path_cam1}$2$3$1″
PerlAddVar ProxyHTMLRewrite “(\”)(\/)(RPC2\_Loadfile|RPC2_Notify_Method) $1$2${path_cam1}$2$3″
PerlAddVar ProxyHTMLRewrite “(rtspoverwebsocket) ${path_cam1}\/$1”
#cerramos la definición del directorio
</Location>
La anterior mecánica se debería replicar para todas las cámaras que se tengan.
NOTA: Esta re-escritura a sido probada en cámaras DH-IPC-HFW1431S1N-S4 V2.820.0000000.48, por lo tanto es probable que en otros modelos sean necesarias algunas modificaciones.
Por ultimo mencionar algunas herramientas utilizadas para lograr este objetivo:
- tcpdump
- Wireshark
- Herramientas de desarrollador Mozilla Firefox
- https://regex101.com/
Con esto finalizamos esta entrada, como siempre si hay alguna duda pueden contactarnos a través de nuestras redes sociales, whatsapp, telegram o nuestro menú de contacto en nuestra pagina web.