Automatizando parámetros en Linux
En muchas ocasiones nos ha sucedido que necesitamos cambiarle los parámetros a nuestra red local, bien sea porque el proveedor de internet cambió las ips, o porque vamos a reemplazar nuestro esquema de red, en fin, hay millones de razones para hacerlo. Sin embargo esta operación puede resultar tediosa, ya que por lo general existen un sinnúmero de programas y servicios que dependen de esta información para su funcionamiento.
Si se trata de un simple equipo conectado a una red local, los cambios serían mínimos, pero si hablamos de un servidor en producción bajo GNU/Linux, como un proxy o un servidor web, etc, la cosa se puede complicar.
Por ejemplo, para el caso de un proxy con dhcp y firewall incluidos, no solo debemos modificar el interfaces, sino los archivos de configuración de dhcp, dnsmask, Apache o Nginx (si corre un servidor web), iptables, Squid, los archivos de configuración de programas de monitoreo, como Munix, Sqstat, Sarg, Ntop-ng, y un muy largo etc. Esto significa que debemos ingresar al terminal e ir modificando uno por uno estos archivos, y como a muchos nos sucede, casi siempre olvidamos uno que otro y el resultado es que nuestro server puede fallar.
Por ejemplo, para el caso de un proxy con dhcp y firewall incluidos, no solo debemos modificar el interfaces, sino los archivos de configuración de dhcp, dnsmask, Apache o Nginx (si corre un servidor web), iptables, Squid, los archivos de configuración de programas de monitoreo, como Munix, Sqstat, Sarg, Ntop-ng, y un muy largo etc. Esto significa que debemos ingresar al terminal e ir modificando uno por uno estos archivos, y como a muchos nos sucede, casi siempre olvidamos uno que otro y el resultado es que nuestro server puede fallar.
Automatizando los cambios de parámetros en un servidor linux
Primero identificamos cuáles son los programas y servicios de nuestro servidor, susceptibles a verse afectados por un cambio de parámetros (en este caso, de red). Por ejemplo, si tenemos un servidor proxy con squid, que genera direcciones ip con DHCP, y que tiene algunos aplicativos webs que dependen de apache, entonces los archivos a modificar serían:
/etc/network/interfaces (cambio de la ip de las tarjetas de red)
/etc/hosts (contiene ips y nombre del servidor)
/etc/squid3/{cachemgr,squid}.conf (contiene los datos del servidor proxy y su acceso al cache manager)
/etc/dhcp/{dhcpd,dhclient,dhcpd}.conf (contiene los datos de la interface de red local para dhcp e información adicional referente al servidor dhcp)
/etc/resolv.conf (contiene los DNS. En este caso puede variar en dependencia del sistema operativo, la versión y el aplicativo que lo genera. Para las versiones de Ubuntu 14x es generado por el aplicativo resolvconf)
/etc/apache2/apache2.conf (contiene la configuración del servidor apache)
Entonces solo faltaría crear un script ponerle un nombre y guardarlo (ejemplo: cambiarparametros.sh), darle permisos sudo chmod +x y ejecutarlo, similar al siguiente:
#!/bin/bash # By Maravento.com. # Special Thanks to Novatoz.com and Alterserv.com # # CAMBIANDO PARAMETROS DE RED DEL SERVIDOR ## # # rutas squid=/etc/squid3 dhcp1=/etc/dhcp dhcp2=/etc/default etc=/etc network=/etc/network initd=/etc/init.d apache2=/etc/apache2 function backupconf(){ ZIPNAME="backup_$(date +%Y%m%d_%H%M).zip" sleep 1 zip ~/$ZIPNAME $network/interfaces $etc/hosts $squid/{cachemgr,squid}.conf $etc/resolv.conf $apache2/apache2.conf $dhcp1/{dhcpd,dhclient}.conf $dhcp2/isc-dhcp-server $etc/sysctl.conf $etc/resolv.conf date=`date +%d/%m/%Y" "%H:%M:%S` } backupconf ask() { pregunta="$1" respuesta_incorrecta="$2" funcion="$3" while true; do read -p "$pregunta: " answer case $answer in [Ss]* ) # execute command yes while true; do answer=`$funcion` if [ "$answer" ]; then echo $answer break; else echo "$respuesta_incorrecta" fi done; break;; [Nn]* ) # execute command no break;; * ) echo; echo "Por favor responda SI (s) o NO (n).";; esac done } # IP-GATEWAY function is_ip(){ read -p "Introduzca la nueva IP (Ejemplo: 192.168.1.10): " IP IPNEW=`echo $IP | egrep '^(([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$'` if [ "$IPNEW" ]; then sed -i "s:192.168.1.10:$IPNEW:g" $network/interfaces $etc/hosts $squid/{cachemgr,squid}.conf $etc/resolv.conf $apache2/apache2.conf echo "Ha introducido correctamente la nueva IP $IP" fi } # MASCARA function is_mask1(){ read -p "Introduzca la nueva mascara de red (Ejemplo: 255.255.255.0): " MASK1 MASKNEW1=`echo $MASK1 | egrep '^(([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$'` if [ "$MASKNEW1" ]; then sed -i "s:255.255.255.0:$MASKNEW1:g" $dhcp1/dhclient.conf $network/interfaces echo "Ha introducido correctamente la mascara $MASK1" fi } function is_mask2(){ read -p "Introduzca la nueva mascara de subred (Ejemplo: 24): " MASK2 MASKNEW2=`echo $MASK2 | egrep '[0-9]'` if [ "$MASKNEW2" ]; then sed -i "s:/24:/$MASKNEW2:g" $squid/squid.conf echo "Ha introducido correctamente la mascara $MASK2" fi } # DNS function is_dns1(){ read -p "Introduzca el DNS1 (Ejemplo: 8.8.8.8): " DNS1 DNSNEW1=`echo $DNS1 | egrep '^(([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$'` if [ "$DNSNEW1" ]; then sed -i "s:8.8.8.8:$DNSNEW1:g" $squid/squid.conf $etc/resolv.conf $network/interfaces echo "Ha introducido correctamente el DNS1 $DNS1" fi } function is_dns2(){ read -p "Introduzca el DNS2 (Ejemplo: 8.8.4.4): " DNS2 DNSNEW2=`echo $DNS2 | egrep '^(([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$'` if [ "$DNSNEW2" ]; then sed -i "s:8.8.8.8:$DNSNEW1:g" $squid/squid.conf $etc/resolv.conf $network/interfaces echo "Ha introducido correctamente DNS2 $DNS2" fi } # LOCALNET function is_localnet(){ read -p "Introduzca el nuevo localnet-network (Ejemplo: 192.168.1.0): " LOCALNET LOCALNETNEW=`echo $LOCALNET | egrep '^(([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$'` if [ "$LOCALNETNEW" ]; then sed -i "s:192.168.1.0:$LOCALNETNEW:g" $squid/squid.conf $network/interfaces echo "Ha introducido correctamente el nuevo localnet-network $LOCALNET" fi } # BROADCAST function is_broadcast(){ read -p "Introduzca el nuevo broadcast (Ejemplo: 192.168.1.255): " BROADCAST BROADCASTNEW=`echo $BROADCAST | egrep '^(([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$'` if [ "$BROADCASTNEW" ]; then sed -i "s:192.168.1.255:$BROADCASTNEW:g" $network/interfaces echo "Ha introducido correctamente el broadcast $BROADCAST" fi } # PUERTO function is_port(){ read -p "Introduzca el nuevo puerto (Ejemplo: 3128): " PORT PORTNEW=`echo $PORT | egrep '[1-9]'` if [ "$PORTNEW" ]; then sed -i "s:3128:$PORTNEW:g" $squid/{cachemgr,squid}.conf echo "Ha introducido correctamente el puerto $PORT" fi } # INTERFAZ DHCP function is_eth(){ read -p "Introduzca la nueva interfaz ethernet para DHCP (Ejemplo: 2): " ETH ETHNEW=`echo $ETH | egrep '[0-9]'` if [ "$ETHNEW" ]; then sed -i "s:eth1:eth$ETHNEW:g" $dhcp2/isc-dhcp-server $etc/sysctl.conf echo "Ha introducido correctamente la interfaz para DHCP $ETH" fi } # RANGO DHCP function is_rangeini(){ read -p "Introduzca la nueva ip para el rango inicial dhcp (Ejemplo: 192.168.1.50): " RANGEINI RANGEININEW=`echo $RANGEINI | egrep '^(([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$'` if [ "$RANGEININEW" ]; then sed -i "s:192.168.1.50:$RANGEININEW:g" $dhcp1/dhcpd.conf echo "Ha introducido correctamente la ip $RANGEINI" fi } function is_rangefin(){ read -p "Introduzca la nueva ip para el rango final dhcp (Ejemplo: 192.168.1.250): " RANGEFIN RANGEFINNEW=`echo $RANGEFIN | egrep '^(([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$'` if [ "$RANGEFINNEW" ]; then sed -i "s:192.168.1.250:$RANGEFINNEW:g" $dhcp1/dhcpd.conf echo "Ha introducido correctamente la ip $RANGEFIN" fi } clear while true; do read -p "Parametros del servidor: ip-port 192.168.1.10:3128, mask 255.255.255.0 /24, DNS 8.8.8.8,8.8.4.4, dhcp eth1, localnet 192.168.1.0, broadcast 192.168.1.255, range-dhcp 50-250 Desea cambiar estos parametros? (s/n)" answer case $answer in [Ss]* ) # execute command yes is_ask "Desea cambiar la IP 192.168.1.10? (s/n)" "Ha introducido una IP incorrecta" is_ip is_ask "Desea cambiar la mascara 255.255.255.0? (s/n)" "Ha introducido una mascara incorrecta" is_mask1 is_ask "Desea cambiar la mascara /24? (s/n)" "Ha introducido una mascara incorrecta" is_mask2 is_ask "Desea cambiar el DNS1 8.8.8.8? (s/n)" "Ha introducido DNS1 incorrecto" is_dns1 is_ask "Desea cambiar el DNS2 8.8.4.4? (s/n)" "Ha introducido DNS2 incorrecto" is_dns2 is_ask "Desea cambiar el localnet 192.168.1.0? (s/n)" "Ha introducido localnet incorrecto" is_localnet is_ask "Desea cambiar el broadcast 192.168.1.255? (s/n)" "Ha introducido un broadcast incorrecto" is_broadcast is_ask "Desea cambiar interfaz ethernet para DHCP eth1? (s/n)" "Ha introducido una interfaz incorrecta" is_eth is_ask "Desea cambiar el puerto del proxy 3128? (s/n)" "Ha introducido un puerto incorrecto" is_port is_ask "Desea cambiar el rango dhcp inicial 192.168.1.50? (s/n)" "Ha introducido una ip incorrecta" is_rangeini is_ask "Desea cambiar el rango dhcp final 192.168.1.250? (s/n)" "Ha introducido una ip incorrecta" is_rangefin echo OK break;; [Nn]* ) # execute command no break;; * ) echo; echo "Por favor responda SI (s) o NO (n).";; esac done
El script anterior, primero hace una copia de seguridad de los archivos que va a reemplazar (opcional), enviándolos a la carpeta /home con el formato
backup_$(date +%Y%m%d_%H%M).zip. También podemos eliminar esto del script y hacer el backup directamente en la misma ruta que se genera el cambio, antes de hacerlo, por ejemplo:
cp /etc/network/interfaces{,.bak}
Luego procedemos a reemplazar los parámetros del servidor. A modo de ejemplo, el script trae los que se relacionan a continuación, los cuales deberá cambiar por los reales de su servidor:
ip-port 192.168.1.10:3128, mask 255.255.255.0 /24, DNS 8.8.8.8,8.8.4.4, dhcp eth1, localnet 192.168.1.0, broadcast 192.168.1.255, range-dhcp 192.168.1.50-192.168.1.250
Una vez reemplazada la información, cada vez que queramos introducir nuevos parámetros de red, solo tendremos que correr el script con privilegios, introducirlos manualmente cuando el script nos haga la pregunta y automáticamente reemplazará los datos de los archivos de configuración establecidos en el script.
También podemos agregar más parámetros de acuerdo a los aplicativos que tengamos que necesiten modificación; por ejemplo, para el caso de resolvconf en Ubuntu podemos agregar la siguiente línea:
# DNS RESOLV function is_resolv1(){ read -p "Introduzca el nuevo DNS resolv 1 (Ejemplo: 8.8.8.8): " RESOLV1 RESOLV1NEW=`echo $RESOLV1 | egrep '^(([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$'` if [ "$RESOLV1NEW" ]; then sed -i "s:8.8.8.8:$RESOLV1NEW:g" /etc/resolvconf/resolv.conf.d/head echo "Ha introducido correctamente el nuevo DNS resolv $RESOLV1" fi } function is_resolv2(){ read -p "Introduzca el nuevo DNS resolv 2 (Ejemplo: 8.8.8.4.4): " RESOLV2 RESOLV2NEW=`echo $RESOLV2 | egrep '^(([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$'` if [ "$RESOLV2NEW" ]; then sed -i "s:8.8.4.4:$RESOLV2NEW:g" /etc/resolvconf/resolv.conf.d/head echo "Ha introducido correctamente el nuevo DNS resolv $RESOLV2" fi }Y más abajo agregamos...
is_ask "Desea cambiar el DNS1 resolv 8.8.8.8? (s/n)" "Ha introducido una ip incorrecta" is_resolv1 is_ask "Desea cambiar el DNS2 resolv 8.8.8.8? (s/n)" "Ha introducido una ip incorrecta" is_resolv2Y si no me acuerdo dónde están los archivos a modificar...
Supongamos que no somos expertos, o algo olvidadizos (a cualquiera le pasa) y no tenemos claro cuántos archivos se verían afectados si realizamos un cambio en los parámetros de red de nuestro servidor. Pues el comando find nos puede ayudar a localizar el archivo con la información a reemplazar, sin necesidad de brindarle el path directo al archivo objeto de modificación.
Por ejemplo, queremos cambiar la IP de nuestro servidor, pero no sabemos cuántos archivos hay que modificar para que funcione correctamente (interfaces, squid, iptables, apache, etc, etc). En este caso, buscamos en el script la línea function is_ip, donde dice:
Por ejemplo, queremos cambiar la IP de nuestro servidor, pero no sabemos cuántos archivos hay que modificar para que funcione correctamente (interfaces, squid, iptables, apache, etc, etc). En este caso, buscamos en el script la línea function is_ip, donde dice:
sed -i "s:192.168.1.10:$IPNEW:g" $network/interfaces $etc/hosts $squid/{cachemgr,squid}.conf $etc/resolv.conf $apache2/apache2.confY la reemplazamos por esta otra...
find / -type f -print0 | xargs -0 -I "{}" sed -i "s:192.168.1.10:$IPNEW:g" "{}"El comando find / -type f -print0 | xargs -0 -I "{}" sed -i "s:192.168.1.10:$IPNEW:g" "{}" buscará en todo el disco duro de su servidor, de forma recursiva, cualquier archivo que contenga la IP 192.168.1.10 y la reemplazará por la ip que introduzcamos manualmente, cuando el script nos diga " Introduzca la nueva IP (Ejemplo: 192.168.1.10):", sin embargo una búsqueda así, solo Dios sabe cuánto tiempo tardaría y lo más seguro es que se trague literalmente los recursos de su sistema, y puede generar errores de archivos temporales bloqueados por root, así que es mejor focalizarla.
Por ejemplo, si sabemos que los archivos a modificar pueden estar en el directorio /etc entonces modificamos el parámetro de búsqueda, quedando así:
find /etc -type f -print0 | xargs -0 -I "{}" sed -i "s:192.168.1.10:$IPNEW:g" "{}"
Incluso podemos limitarla aún más, para que el resultado aparezca más rápido, con las opciones -maxdepth y -name (Para más información lea man find).
Por ejemplo, podemos especificar que busque hasta tres directorios debajo de /etc, y solo en los terminados con extensión .conf. Entonces, la línea modificada quedaría así:
Por ejemplo, podemos especificar que busque hasta tres directorios debajo de /etc, y solo en los terminados con extensión .conf. Entonces, la línea modificada quedaría así:
find /etc -maxdepth 3 -name '*.conf' -type f -print0 | xargs -0 -I "{}" sed -i "s:192.168.1.10:$IPNEW:g" "{}"
También podemos cambiarle el nombre a nuestro servidor (letras, números o guión abajo)
Supongamos que tenemos una copia de los archivos hosts y hostname guardados en /home/prueba, pero con nombres diferentes al que tenemos en nuestro servidor (pueden hacerlo con cualquier otro archivo de configuración). Luego modificamos la función y le agregamos dicho nombre donde dice nombre_prueba.
La función, una vez se ejecute, cambiará este "nombre_ prueba" por el verdadero nombre de su servidor y reemplazará los archivos hosts y hostname (haciendo un backup antes):
# NOMBRE function is_name(){ read -p "Introduzca el nuevo nombre del servidor (Ejemplo: usuario): " NAME NAMENEW=`echo $NAME | egrep '^\w+$'` if [ "$NAMENEW" ]; then # puede elegir esta: find /etc -maxdepth 1 -type f -print0 | xargs -0 -I "{}" sed -i "s:usuario:$NAME:g" "{}" # o esta: # sed -i "s:usuario:$NAMENEW:g" /etc/{hosts,hostname} echo "Ha introducido correctamente el nuevo nombre $NAME" fi } # y agregamos al final del script is_ask "Desea cambiarle el nombre al servidor "usuario"? (s/n)" "Ha introducido un nombre incorrecto" is_nameUna función más universal es la que utilizamos en el proyecto GateProxy para el cambio de nombre en el servidor.
Supongamos que tenemos una copia de los archivos hosts y hostname guardados en /home/prueba, pero con nombres diferentes al que tenemos en nuestro servidor (pueden hacerlo con cualquier otro archivo de configuración). Luego modificamos la función y le agregamos dicho nombre donde dice nombre_prueba.
La función, una vez se ejecute, cambiará este "nombre_ prueba" por el verdadero nombre de su servidor y reemplazará los archivos hosts y hostname (haciendo un backup antes):
# CAMBIO DE NOMBRE function is_name(){ is_user=`echo $HOSTNAME` if [ "$is_user" ]; then find ~/prueba -type f -print0 | xargs -0 -I "{}" sed -i "s:nombre_prueba:$is_user:g" "{}"gateproxy/conf/ cp /etc/hosts{,.bak} >/dev/null 2>&1 cp /etc/hostname{,.bak} >/dev/null 2>&1 cp ~/carpeta/{hosts,hostname} /etc/{hosts,hostname} fi } is_nameComo podemos ver, es fácil adaptar este script a nuestras necesidades, de acuerdo a lo que queramos modificar Y si es paranoico, puede agregarle un mecanismo de verificación de la aplicación o servicio concreto a modificar; por ejemplo que el script verifique si existe o no el servidor apache antes de realizar algún cambio, de lo contrario que aborte. En este caso, le podríamos agregar un parámetro similar a:
if [[ `ps -A | grep apache2` != "" ]];thenY no olviden reiniciar su equipo para que tome los cambios.
Obtención de IPs
En el post Firewall, abordamos el tema sobre darle "algo de seguridad" a un proxy transparente, basado en Squid-Cache, filtrando el puerto 443 con iptables. Es importante resaltar que como Squid no filtra peticiones https cuando se encuentra en modo transparente, cualquier cosa dirigida al puerto 443, no será procesada por este proxy (y tampoco aparecerá en ningún reporte, como Sarg, Sqstat, etc).
En dicho post propusimos crear una regla de iptables que solo valide (permita) entrar a nuestra red local aquellas ips que nos interesan (asociadas a sitios webs https) y denegar el resto, sin embargo, como la moda ahora es "todo por https" ( Google prioriza la indexación https), nuestras listas de ips https pueden pasar de los cientos a los cientos de miles, y eventualmente puede convertirse en una pesadilla logística obtener todas estas ips.
En su momento propusimos varias maneras de obtenerlas, las cuales enumeraremos a continuación:
1. METODO MANUAL
a. Comandos:
originAS es la información asociada a un dominio o ip. Se puede obtener de varias maneras:
a. Manualmente
En centralops.net/co/ buscamos el dominio (Ej: facebook.com) y en los resultados aparecerá el originAS. Luego ejecutamos en consola:
También existen sitios y herramientas donde consultar los ASN.
b. Script
Haciendo uso de whois.radb.net, (y whois.arin.net) utilizamos un script como el propuesto por el portal Karpoke
Pros: Ahorra mucho tiempo en la obtención de ips y amplia el rango de posibilidades de validación (o bloqueo) de las ips asociadas a un domino.
Contra: No siempre se obtiene el originAS o CIDR. Whois puede bloquear peticiones masivas. Durante la ejecución del script podemos obtener mensajes como:
ANALISIS
En este punto es prudente hacernos una pregunta: ¿Que tanto necesitamos todos rangos de ips asociados a un domino?
Muchos responderán que ahorra mucho trabajo y tiempo, sin embargo veamos el siguiente escenario.
Supongamos que tenemos un firewall y vamos a realizar un bloqueo masivo de ips. Sin embargo necesitamos validar todos los rangos de ips asociadas al dominio google.com y ponerlos en nuestra "lista blanca", para excluirlos de este bloqueo y así los usuarios puedan ingresar a google.com.
Debemos saber que, aparte de los servicios que ofrece google expresados en subdominios ( doc.google.com, drive.google.com, etc), también existen cientos de dominios tipo "com.algo" en dependencia del país (www.google.com.ve, com.br, com.co, etc)
Ahora imaginemos que vivimos en México (puede ser cualquier país) y la "lista blanca" la vamos a usar en ese país. Entonces, ¿para qué necesitamos validar en nuestra lista los dominios google.com.br (brasil) o google.com.co (colombia), y similares?
Si tenemos una lista de control de acceso ACL, bien sea para nuestro firewall, route, servidor, proxy, etc, introducirle el rango asociado a google.com.br estando la infraestructura en México no tendría mucho sentido, ya que las peticiones hacia cualquier dominio, por lo general, siempre buscan el camino más corto o se redireccionan al servidor más cercano al punto de la petición, en este caso, las peticiones a google.com se redireccionan a google.com.mx. Y este mismo esquema lo utilizan infinidades de dominios.
Pero, a pesar de esto, muchos administradores IT tienen la costumbre de validar todos y cada uno de los rangos que existen de google, yahoo, microsoft, etc, trayendo como consecuencia la ralentización de su red, ya que por cada rango de ips que le introduzcamos a nuestro hardware o software de administración de red, será un procesamiento adicional y/o consulta que tendrá que hacer por cada petición que un usuario realice dentro de la red local, generando también un consumo excesivo de recursos y de ancho de banda (que implican estas consultas masivas), y si lo hacemos con regularidad, pueden tachar a nuestro servidor como scam, bot o cualquier otra cosa y meterlo en alguna blacklist.
Para una mayor comprensión de este problema, observemos solamente el ASN del dominio google.com ( AS15169), el cual contiene nada mas y nada menos que 1,247,488 direcciones ips. Y cada una de ellas deberá ser procesada por nuestro firewall o proxy, para cada una de las peticiones que haga un cliente. Ya podrán imaginar el volumen y la capacidad de procesamiento. Y hablamos de un solo dominio...
Por último, muchos dominios, como Google, tienen rangos dinámicos (cambian rangos de ips sin previo aviso), y hoy es muy usual que las empresas y proveedores de internet, cambien constantemente sus rangos de ips (y servidores), con el objeto de protegerse de un ataque prolongado DDoS y así balancear cargas y no interrumpir sus servicios, y los antiguos rangos son revendidos, segmentados y/o reasignados a otras empresas, ya que en la mayoría de los casos son servidores compartidos.
Además, todo el rango de ips asociadas a un dominio no necesariamente puede ser utilizado por el mismo y desafortunadamente muchos administradores IT van dejando estos rangos obsoletos en sus listas de control de acceso, lo cual ralentiza aún más la red local y eventualmente pueden convertirse en un problema de seguridad (ya que los rangos pueden ser revendidos a una organización con fines maliciosos)
En resumen, los dominios (o si prefieren llamarlos sitios web / urls) por lo general no sufren muchos cambios significativos y más bien se amplían (net, org, crean nuevos subdominios, se redireccionan etc), pero sus rangos de ips sí cambian constantemente. Por tal razón, hoy por hoy, los métodos anteriormente descritos, así como cualquier otro método que involucre rangos masivos de ips (basados en CIDR/OriginAS), consideramos que no son del todo viables y creemos que es más factible utilizar métodos que capturen únicamente las IPs asociadas a un dominio, ya que son mucho más seguros y fáciles de renovar.
AUTOMATIZANDO LA OBTENCIÓN DE IPS
En el post Firewall, abordamos el tema sobre darle "algo de seguridad" a un proxy transparente, basado en Squid-Cache, filtrando el puerto 443 con iptables. Es importante resaltar que como Squid no filtra peticiones https cuando se encuentra en modo transparente, cualquier cosa dirigida al puerto 443, no será procesada por este proxy (y tampoco aparecerá en ningún reporte, como Sarg, Sqstat, etc).
En dicho post propusimos crear una regla de iptables que solo valide (permita) entrar a nuestra red local aquellas ips que nos interesan (asociadas a sitios webs https) y denegar el resto, sin embargo, como la moda ahora es "todo por https" ( Google prioriza la indexación https), nuestras listas de ips https pueden pasar de los cientos a los cientos de miles, y eventualmente puede convertirse en una pesadilla logística obtener todas estas ips.
En su momento propusimos varias maneras de obtenerlas, las cuales enumeraremos a continuación:
1. METODO MANUAL
a. Comandos:
nslookup google.com dig +short google.com host -t a google.comb. Herramientas y/o sitios webs
Socketsniff es una herramienta muy efectiva y simple. Iniciamos el programa que queremos saber la ip a la cual se conecta (ej: Skype). Después de iniciado, arrancamos Sockersniff y elegimos Skype. Seguido ponemos el usuario y la contraseña en Skype y comienza la autenticación normal, y Sockersniff va registrando todos las ip a las que Skype intenta conectarse y otros datos como el puerto que usa, etc. Tomamos nota de las IPs y vamos a nuestra ACL correspondiente (bloquear o aceptar) y las validamos.
Lo mismo con los sitios en Internet. Abrimos el navegador. Elegimos en Sockersniff el navegador a monitorear, y luego vamos a la página deseada, para que Sockersniff detecte la IP y el resto es el mismo procedimiento que con los programas.
En ocasiones las IPs son similares, lo cual nos indica que hay un rango más amplio de IPs que usa nuestro programa o sitio web que queremos bloquear o aceptar. Para saberlo vamos a IP Adrdress Lockup, y buscamos las IPs, subiendo y bajando los octetos de valor decimal, para ir verificando el propietario o usuario de la IP, hasta completar el rango. También pueden usar Whois Lockup, o cualquier otra herramienta que gusten para determinar las IPs objetivo, siempre que brinden resultados confiables.
Pros: Ambas alternativas son muy fiables en los resultados
Contras: Los comandos se deben ejecutar varias veces (con y sin www) para cada dominio, ya que los resultados podrían variar.
Socketsniff no funciona en sistemas x64 y tiene dificultades para capturar ips de aplicaciones y sitios cifrados y en algunos navegadores no ofrece resultados.
2. CIDR/ORIGINAS
En ocasiones las IPs son similares, lo cual nos indica que hay un rango más amplio de IPs que usa nuestro programa o sitio web que queremos bloquear o aceptar. Para saberlo vamos a IP Adrdress Lockup, y buscamos las IPs, subiendo y bajando los octetos de valor decimal, para ir verificando el propietario o usuario de la IP, hasta completar el rango. También pueden usar Whois Lockup, o cualquier otra herramienta que gusten para determinar las IPs objetivo, siempre que brinden resultados confiables.
Pros: Ambas alternativas son muy fiables en los resultados
Contras: Los comandos se deben ejecutar varias veces (con y sin www) para cada dominio, ya que los resultados podrían variar.
Socketsniff no funciona en sistemas x64 y tiene dificultades para capturar ips de aplicaciones y sitios cifrados y en algunos navegadores no ofrece resultados.
originAS es la información asociada a un dominio o ip. Se puede obtener de varias maneras:
a. Manualmente
En centralops.net/co/ buscamos el dominio (Ej: facebook.com) y en los resultados aparecerá el originAS. Luego ejecutamos en consola:
/usr/bin/whois -h whois.radb.net '!gAS32934' | tr ' ' '\n' | sort -n -k1,1 -k2,2 -k3,3 -k4,4 |grep /Donde AS32934 es el originAS de facebook y arrojará todos los rangos de ips de este dominio.
También existen sitios y herramientas donde consultar los ASN.
b. Script
Haciendo uso de whois.radb.net, (y whois.arin.net) utilizamos un script como el propuesto por el portal Karpoke
for IP in $(dig +short -f domains.txt); do AAS=$(whois $IP | awk -F: '/OriginAS/{print $2}') for AS in $AAS; do AS=${AS%%[^0-9]} test -n "$AS" && whois -h whois.radb.net '!g'$AS | tr -d "\n" | tr " " "\n" done done > final.txtDonde domains.txt es una acl que contiene todos los dominios que queramos saber el OriginAS y final.txt es donde pondremos el resultado y finalmente hacemos una depuración del resultado. También podemos capturar el CIDR, como el propuesto en stackoverflow
for X in `cat domains.txt`; do host -t a $X; done | awk 'BEGIN { FS = " " } ; { print $4 }' > ip.txt; for Y in `cat ip.txt`; do whois $Y | grep CIDR; doneTambién están las calculadoras web como ipaddressguide, ultratools, etc.
Pros: Ahorra mucho tiempo en la obtención de ips y amplia el rango de posibilidades de validación (o bloqueo) de las ips asociadas a un domino.
Contra: No siempre se obtiene el originAS o CIDR. Whois puede bloquear peticiones masivas. Durante la ejecución del script podemos obtener mensajes como:
ANALISIS
En este punto es prudente hacernos una pregunta: ¿Que tanto necesitamos todos rangos de ips asociados a un domino?
Muchos responderán que ahorra mucho trabajo y tiempo, sin embargo veamos el siguiente escenario.
Supongamos que tenemos un firewall y vamos a realizar un bloqueo masivo de ips. Sin embargo necesitamos validar todos los rangos de ips asociadas al dominio google.com y ponerlos en nuestra "lista blanca", para excluirlos de este bloqueo y así los usuarios puedan ingresar a google.com.
Debemos saber que, aparte de los servicios que ofrece google expresados en subdominios ( doc.google.com, drive.google.com, etc), también existen cientos de dominios tipo "com.algo" en dependencia del país (www.google.com.ve, com.br, com.co, etc)
Ahora imaginemos que vivimos en México (puede ser cualquier país) y la "lista blanca" la vamos a usar en ese país. Entonces, ¿para qué necesitamos validar en nuestra lista los dominios google.com.br (brasil) o google.com.co (colombia), y similares?
Si tenemos una lista de control de acceso ACL, bien sea para nuestro firewall, route, servidor, proxy, etc, introducirle el rango asociado a google.com.br estando la infraestructura en México no tendría mucho sentido, ya que las peticiones hacia cualquier dominio, por lo general, siempre buscan el camino más corto o se redireccionan al servidor más cercano al punto de la petición, en este caso, las peticiones a google.com se redireccionan a google.com.mx. Y este mismo esquema lo utilizan infinidades de dominios.
Pero, a pesar de esto, muchos administradores IT tienen la costumbre de validar todos y cada uno de los rangos que existen de google, yahoo, microsoft, etc, trayendo como consecuencia la ralentización de su red, ya que por cada rango de ips que le introduzcamos a nuestro hardware o software de administración de red, será un procesamiento adicional y/o consulta que tendrá que hacer por cada petición que un usuario realice dentro de la red local, generando también un consumo excesivo de recursos y de ancho de banda (que implican estas consultas masivas), y si lo hacemos con regularidad, pueden tachar a nuestro servidor como scam, bot o cualquier otra cosa y meterlo en alguna blacklist.
Para una mayor comprensión de este problema, observemos solamente el ASN del dominio google.com ( AS15169), el cual contiene nada mas y nada menos que 1,247,488 direcciones ips. Y cada una de ellas deberá ser procesada por nuestro firewall o proxy, para cada una de las peticiones que haga un cliente. Ya podrán imaginar el volumen y la capacidad de procesamiento. Y hablamos de un solo dominio...
Por último, muchos dominios, como Google, tienen rangos dinámicos (cambian rangos de ips sin previo aviso), y hoy es muy usual que las empresas y proveedores de internet, cambien constantemente sus rangos de ips (y servidores), con el objeto de protegerse de un ataque prolongado DDoS y así balancear cargas y no interrumpir sus servicios, y los antiguos rangos son revendidos, segmentados y/o reasignados a otras empresas, ya que en la mayoría de los casos son servidores compartidos.
Además, todo el rango de ips asociadas a un dominio no necesariamente puede ser utilizado por el mismo y desafortunadamente muchos administradores IT van dejando estos rangos obsoletos en sus listas de control de acceso, lo cual ralentiza aún más la red local y eventualmente pueden convertirse en un problema de seguridad (ya que los rangos pueden ser revendidos a una organización con fines maliciosos)
En resumen, los dominios (o si prefieren llamarlos sitios web / urls) por lo general no sufren muchos cambios significativos y más bien se amplían (net, org, crean nuevos subdominios, se redireccionan etc), pero sus rangos de ips sí cambian constantemente. Por tal razón, hoy por hoy, los métodos anteriormente descritos, así como cualquier otro método que involucre rangos masivos de ips (basados en CIDR/OriginAS), consideramos que no son del todo viables y creemos que es más factible utilizar métodos que capturen únicamente las IPs asociadas a un dominio, ya que son mucho más seguros y fáciles de renovar.
AUTOMATIZANDO LA OBTENCIÓN DE IPS
En el siguiente ejemplo crearemos una acl llamada whitewebs (puede elegir cualquier otro nombre) y dentro incluiremos todos los dominios http/s que queramos dejar pasar. En el siguiente ejemplo la hemos guardado en la ruta /etc/acl. Los dominios deben estar en el siguiente formato:
# Google google.com google.com.co google.co # Yahoo yahoo.com # etc, etc
Sin embargo si tienen puntos al inicio (como en nuestra ACL. Ej: .google.com), comentarios (#), espacios en blanco, el script los elimina.
Guardamos el script en /etc/init.d/web2ip.sh (puede darle el nombre o la ruta que quieran) y le da permisos root chmod +x.
Finalmente hace una validación y depuración de las ips y el resultado es una ACL final a la cual hemos llamado ips.txt. Puede programar el script en el cron para que se ejecute periódicamente y actualice las ips.
Guardamos el script en /etc/init.d/web2ip.sh (puede darle el nombre o la ruta que quieran) y le da permisos root chmod +x.
#!/bin/bash ### BEGIN INIT INFO # Provides: web2ip # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start daemon at boot time # Description: capture ips from acl # Authors: Maravento.com and Novatoz.com ### END INIT INFO route=/etc/acl tmp=/tmp cat $route/domains.txt | sed '/^$/d; / *#/d' | sed 's:^\.::' | sort -u > $tmp/cleardomains.txt for ip in `cat $tmp/cleardomains.txt`; do for sub in "" "www." "ftp."; do host -t a "${sub}${ip}"; done done | awk 'BEGIN { FS = " " } ; { print $4 }' | egrep -o "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" | sort -u > $route/ips.txt sort -o $route/ips.txt -u $route/ips.txt -t . -k 1,1n -k 2,2n -k 3,3n -k 4,4n $route/ips.txtEl script anterior lo que hace es revisa la ACL domains.txt, elimina cualquier comentario, punto delante o espacio, para que sean dominios válidos de consulta y así evitar el error '.google.com' is not a legal name (empty label) y crea un archivo temporal con los resultados. El script utiliza este archivo temporal para realizar consultas de cada dominio, con y sin el www (incluye también ftp, y puede agregarle manualmente otros tipos de consultas de subdominios), para obtener todas las ips asociadas a los dominios incluidos en la lista.
Finalmente hace una validación y depuración de las ips y el resultado es una ACL final a la cual hemos llamado ips.txt. Puede programar el script en el cron para que se ejecute periódicamente y actualice las ips.
Post a Comment