Header Ads

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 sinnumero 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.
Con la liberación del proyecto GateProxy, nuestra humilde contribución libre para administrar redes locales Home & Business, se nos presentó el dilema de si un usuario quiere instalarlo en su servidor, pero ya tiene una configuración previa.
En las primeras betas no era posible, ya que este proyecto trae unos parámetros preestablecidos (ip, puertos, dns, etc), pero gracias a la ayuda de nuestros partners Novatoz.com y Alterserv.com, pudimos automatizar este proceso con un script, que si bien no es un método universal, es posible adaptarlo a cualquier entorno.
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:
sudo 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_resolv2
Y 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:
sed -i "s:192.168.1.10:$IPNEW:g" $network/interfaces $etc/hosts $squid/{cachemgr,squid}.conf $etc/resolv.conf $apache2/apache2.conf
Y 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í:
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)
# 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_name
Una 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
      sudo cp ~/carpeta/{hosts,hostname} /etc/{hosts,hostname}
   fi
}
is_name
Como 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` != "" ]];then
Y no olviden reiniciar su equipo para que tome los cambios.

Imagen cortesía de wall321.com
Con la tecnología de Blogger.