viernes, 17 de noviembre de 2017

DHCP script para crear dhcpd.conf a partir de la db dhcpd.leases

Se me ha presentado el siguiente escenario: Tengo un servidor ubuntu que distribuye y rutea vlans y estoy en el medio de la elaboración de un plan de contingencia en el cual están comprendidos los router y los switch del MDF.
el BCP (Business Continuity Plan) esta pensado para una situación donde desaparece momentáneamente la topología lógica de Vlan. En el plan de continuidad permanece la subdivisión de redes pero esta ves por la asignación de los datos de configuración directamente por el isc-dhcp-server. Para ello el plan contempla dos tipos de incidentes:
1) fallas en el servidor distribuidor de vlans.
2) fallas en el switch principal con TRUNKs vlan.

 Para esto, configuré un servidor clon del distribuidor de vlans y me ví en la necesidad de crear un script que me permita obtener los datos de los hosts existentes conectados o apagados para asignarle estáticamente su pertenencia a la sub red.
De ello surge el script que explico a continuación.
En Ubuntu la base de datos del servidor dhcp esta en: /var/lib/dhcp/dhcpd.leases
y su configuración en:  /etc/dhcp/dhcpd.conf

el contenido de dhcpd.conf puede ser parecido a este:



y el contenido de dhcpd.leases:



Primero vamos a generar un archivo csv con el script explicado aqui:
http://jaskolowski.com.ar/2017/11/script-para-parsear-dhcpdlease.html

que es este:



nos genera un archivo con un contenido parecido a este:



ese archivo lo vamos a procesar con el siguiente script:



dejo el texto a continuación por si les resulta más fácil copy&paste:

#!/bin/bash
# script para crear dhcpd.conf a partir de la DB dhcpd.leases
#
# Creamos variables para obtener IP, MAC y Gateway de hosts
IP=(`cat lease.csv |cut -f1 -d";"`)
MAC=(`cat lease.csv |cut -f2 -d";"`)
GW=(`cat lease.csv |cut -f1 -d";"|sed 's:[^.]*$:1:'`)

# iniciamos el encabezado de dhcpd.conf

echo "ddns-update-style none;">dhcpd.conf
echo "Authoritative;">>dhcpd.conf
echo "ignore client-updates;">>dhcpd.conf


#creacion de un arreglo
for i in "${!IP[@]}"
do

# creamos cada lease por host
echo "# PC-${IP[$i]}">>dhcpd.conf
echo "Host PC-${IP[$i]} {">>dhcpd.conf
echo "        hardware ethernet               ${MAC[$i]};">>dhcpd.conf
echo "        fixed-address                   ${IP[$i]};">>dhcpd.conf
echo "        option subnet-mask              255.255.255.224;">>dhcpd.conf
echo "        option domain-name-servers      8.8.8.8,208.67.222.222;">>dhcp.conf
echo "        option routers                  ${GW[$i]};">>dhcpd.conf
echo "        default-lease-time -1;">>dhcpd.conf
echo "        max-lease-time -1;">>dhcpd.conf
echo "}">>dhcpd.conf
done
 Y eso nos da como resultado un archivo de configuración de dhcp server que va a asignar a cada host que tiene registrado por su mac la ip correspondiente a la sub red a la que pertenecía en un entorno vlan.

Adicionalmente se puede configurar una sub red para 30 ó 62 hosts que no hayan sido registrados en dhcpd.leases y aunque no esten en la sub red de su vlan, al menos tengan conexión hasta que se concluya el DRP.






miércoles, 15 de noviembre de 2017

Script para parsear dhcpd.lease explicado en detalle

A continuación publico la traducción de este foro:
 https://www.linuxquestions.org/questions/programming-9/parse-dhcpd-leases-to-store-data-in-mysql-577693/page2.html
En el cual se explica con detalle cómo obtener información del archivo dhcpd.lease el cual es la base de datos del ics dhcp server.
 Primero enumeramos las 9 lineas del script para luego explicarlas en detalle una por una.

Script:
1) IP='([0-9]{1,3}\.){3}[0-9]{1,3}'

2) ST='(active|free)'

3) MAC='([0-9a-f]{2}:){5}[0-9a-f]{2}'



4) cat dhcpd.leases \

5) | sed 's,^ *,,' \

6) | egrep '^(lease|binding|hardware)' \

7) | egrep -o "$IP|$ST|$MAC" \

8) | sed -r 'N;N;s,\n(.*)\n(.*),\;\2\;\1,' \

9) > target.csv


Explicación detallada:
0) #! / bin / bash
=> shebang: par de caracteres #!
=> #! este archivo es un script
=> /bin/bash se usará bourne again shell

1) IP='([0-9]{1,3}\.){3}[0-9]{1,3}'
=> variable con expresión regular IP
=> expresión regular es una forma flexible para comparar cadenas de texto
=> con comillas; de lo contrario, se ve como una sola cadena
Principalmente, las comillas simples hacen que la cadena sea literal.
Más tarde, se usarán comillas dobles para permitir la sustitución de variables en una cadena.

Tenga en cuenta que '\' delante de '.', Asegura que cuando la variable se usa como expresión regular,
el '.' se interpretará literalmente, no como un comodín regex.
=> () agrupación, evalúa primero lo que está entre ()
=> [] condición
=> [0-9] llaves cuadradas para que coincida con un rango de caracteres, si los caracteres están separados por un guión
=> {1,3} {N, M} El elemento anterior se empareja al menos N veces, pero no más de M veces.
=> {3} {N} El elemento anterior coincide exactamente con N veces.

2) ST='(active|free)'
=> variable con dos estados posibles
=> | separa las palabras
Si nos preocupamos por todos los estados posibles, esto hubiera sido:
ST = '(libre | activo | expirado | liberado | abandonado | restablecido | copia de seguridad | reservado | bootp)'

3) MAC='([0-9a-f]{2}:){5}[0-9a-f]{2}'
=> variable con expresión regular MAC

4) cat dhcpd.leases \
=> Concatenar ARCHIVO, a salida estándar, o en tubería
Esta línea no es necesaria, el nombre del archivo fuente podría ser un argumento para el siguiente comando. Lo hice así por claridad.
Del mismo modo, la tubería podría haber sido colocada en una línea larga, puse cada
pipe en una línea separada para mayor claridad.
Nota: la '\' en los extremos de estas líneas funciona como caracteres de continuación,

siempre y cuando
él realmente sea el ÚLTIMO caracter en la línea.
Finalmente, elijo la tubería, '|', al comienzo de la siguiente línea,

en lugar del final de la anterior para
mejor estética, claridad y conveniencia de destacar las piezas durante la prueba.
    Código:
      gato ... \
     |  sed ... \ 
    vs.
    Código:
      gato ... |
     sed ... | 




5) | sed 's,^ *,,' \
Este es un preprocesador que garantiza que el egrep en la línea siguiente funcionará correctamente.
=> El Stream EDitor se utiliza para realizar transformaciones básicas en la lectura de texto de un archivo o un conducto. El resultado se envía a la salida estándar.
=> s Buscar y reemplazar texto (sustitución)
=> ^ coincide con una nueva línea
coincide con el comienzo de una línea
=> * El elemento anterior , un espacio, se emparejará cero o más veces
=> ,,
La forma "normal" para una expresión regular de sustitución es "s ///",
cualquier caracter puede ser usado -- la 1ra cosa después de 's' se conviert
e en el delimitador.
La persona que comenzó a enseñarme
sed prefirió las comas por razones estéticas:
- Compare "s/\/\/\//\/\//"
con "s,///,//,"…

6) | egrep '^(lease|binding|hardware)' \
=> egrep busca un patrón que es una expresión regular extendida
=> ^ coincide con todo, excepto un espacio
No en este contexto, el '^' coincide con la cadena nula al comienzo de una línea.
=> ^ en este caso coincide con el lease sugerido, enlace, hardware
Solo coincide con las palabras de destino si ocurren al comienzo de la línea,
esta es la razón por la cual
sencillo sed anterior es necesario.

7) | egrep -o "$IP|$ST|$MAC" \
=> -o Muestra solo la parte que coincide, de una línea coincidente
Una de las mejores banderas que conozco


8) | sed -r 'N;N;s,\n(.*)\n(.*),\;\2\;\1,' \
=> -r usa expresiones regulares en el script
Desde la página man: "usar expresiones regulares extendidas en el script".
La distinción es importante: lo hace actuar como egrep ,
de lo contrario, los metacaracteres "() {}" tendrían que ser escapados, es decir, precedidos por un '\'.

=> N no imprimir
'N' agrega la siguiente línea de entrada al espacio del patrón.
"-n" es la bandera de no imprimir.
=> \ n nuevo carácter de línea

9) > target.csv
=>> salida a target.csv

Como dije antes, este script es frágil.
Es frágil porque no intenta validar su entrada; entonces, si cualquiera de mis suposiciones es incorrecta, puede dar resultados impredecibles. Siempre que se use en el contexto para el que fue escrito, debería funcionar como se esperaba.