Servidor DHCP con Vagrant

¿Qué vamos a ver?

En esta entrada vamos a ver como montar un servidor dhcp en una máquina debian montada con Vagrant. Proviene de un ejercicio que nos planteó nuestro profesor en la asignatura de «servicios de red e internet«. En el siguiente enlace podéis ver el ejercicio completo:  http://josedom24.github.io/mod/serviciosgs/e_dhcp_4

Teoria

El cliente en estado INIT contacta con el servidor dhcp y envía un DHCPDISCOVER a la dirección broadcast 255.255.255.255. Este mensaje es encapsulado en un paquete UDP con puerto 67. El cliente dhcp espera entre 1 y 10 segundos hasta volver a enviar un nuevo DHCPDISCOVER para envitar uan colisión con otro cliente.

Después de enviar este mensaje el cliente pasa a un estado SELECTING en el que deberá aceptar un paquete DHCPOFFER enviado por el servidor.

Una vez elegido este paquete DHCPOFFER, el cliente envía una paquete DHCPREQUESTS para elegir su servidor DHCP, a lo que contestará el servidor con un mensaje DHCPACK.

En el caso de que se hubiera elegido una ip duplicada, el cliente envía un paquete DHCPDECLINE y vuelve al estado INIT.

Si el paquete DHPACK es aceptado, el cliente pasa al estado BOUND, en el que recibirá un T1,T2 y T3, donde:

• T1 es el temporizador de renovación de alquiler.
• T2 es el temporizador de reenganche.
• T3 es la duración del alquiler.

Una vez que T1 expira, el cliente pasa al estado RENEWING  en el que se negocia de nuevo la asignación de ip.

Si el servidor no renueva la ip, le enviará un mensaje DHCPNACK y el cliente volverá al estado INIT e intentará obtener una ip de nuevo.

Si el servidor renueva la ip, le enviará de nuevo un mensaje DHCPACK con nuevos valores en T1,T2 y T3. De nuevo el cliente pasa al estado BOUND.

Si T2 expira mientras el cliente DHCP está esperando en el estado RENEWING, el cliente pasará al estado REBINDING en el que envia de nuevo un DHCPREQUEST a cualquier  servidor. Si un servidor contesta con un DHCPACK, el cliente renueva su ip y sus temporizadores y pasa al estado BOUND.

En el caso de que no hubiese respuesta de ningún servidor dhcp, el cliente pasa al estado INIT para buscar un nuevo servidor.

Preparación del escenario

Crea un escenario usando Vagrant que defina las siguientes máquinas:

  • Servidor: Tiene dos tarjetas de red: una pública y una privadas que se conectan a la red local.

  • nodo_lan1: Un cliente conectado a la red local.

Creamos un directorio nuevo en el que hacemos «vagrant init«, ahora procedemos a modificar el fichero Vagrantfile dejándolo de la siguiente forma:

# -*- mode: ruby -*-
# vi: set ft=ruby :

VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

  config.vm.define :servidor do |servidor|
    servidor.vm.box = "precise64"
    servidor.vm.hostname = "Servidor"
    servidor.vm.network "public_network",:bridge=>"eth0"
    servidor.vm.network "private_network", ip: "192.168.100.1",
      virtualbox__intnet: "redinterna"
  end
  config.vm.define :nodo_lan1 do |nodo_lan1|
    nodo_lan1.vm.box = "precise64"
    nodo_lan1.vm.hostname = "NodoLan1"
    nodo_lan1.vm.network "private_network", type: "dhcp",
      virtualbox__intnet: "redinterna"
  end
end

En el fichero hemos definido 2 máquinas, una llamada «servdidor» y otra «nodo_lan1«.

Configuramos la máquina «servidor» para que tenga 2 interfaces de red, una en modo puente y otra con ip privada.

La máquina «nodo_lan1» la configuramos para que tenga sólo una interfaz de red en modo dhcp para que obtenga su ip de forma automática.

Incluimos a ambas máquinas en la misma red interna con la linea «virtualbox__intnet: «redinterna»«.

Vemos la configuración de las interfaces en la máquina «servidor«:

eth1 Link encap:Ethernet HWaddr 08:00:27:a3:a1:5f
 inet addr:172.22.10.53 Bcast:172.22.255.255 Mask:255.255.0.0
 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
 RX packets:2852 errors:0 dropped:0 overruns:0 frame:0
 TX packets:11 errors:0 dropped:0 overruns:0 carrier:0
 collisions:0 txqueuelen:1000
 RX bytes:321672 (321.6 KB) TX bytes:1338 (1.3 KB)

eth2 Link encap:Ethernet HWaddr 08:00:27:e6:fc:94
 inet addr:192.168.100.1 Bcast:192.168.100.255 Mask:255.255.255.0
 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
 RX packets:60 errors:0 dropped:0 overruns:0 frame:0
 TX packets:31 errors:0 dropped:0 overruns:0 carrier:0
 collisions:0 txqueuelen:1000
 RX bytes:10740 (10.7 KB) TX bytes:9058 (9.0 KB)

Observamos que las interfaces han sido configuradas correctamente.

Ahora procedemos a ver la interfaz de red en la máquina «nodo_lan1»:

eth1 Link encap:Ethernet HWaddr 08:00:27:6d:a7:38
 inet addr:172.28.128.3 Bcast:172.28.128.255 Mask:255.255.255.0
 inet6 addr: fe80::a00:27ff:fe6d:a738/64 Scope:Link
 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
 RX packets:73 errors:0 dropped:0 overruns:0 frame:0
 TX packets:33 errors:0 dropped:0 overruns:0 carrier:0
 collisions:0 txqueuelen:1000
 RX bytes:17934 (17.9 KB) TX bytes:6422 (6.4 KB)

Podemos ver que la ip proporcionada no está en la misma red de la máquina «servidor» por lo que no tienen conexión  entre sí.

Instalación servidor dhcp

Instala un servidor dhcp en el ordenador “servidor” que de servicio a los ordenadores de red local, teniendo en cuanta que el tiempo de concesión sea 12 horas y que la red local tiene el direccionamiento 192.168.100.0/24.

Para que el cliente  «nodo_lan1» obtenga una ip por dhcp debemos configurar un servidor en la máquina «servidor»

vagrant@Servidor:~$ apt-get install isc-dhcp-server

Modificamos el archivo «/etc/default/isc-dhcp-server« y lo dejamos de la siguiente manera:

# Defaults for dhcp initscript
# sourced by /etc/init.d/dhcp
# installed at /etc/default/isc-dhcp-server by the maintainer scripts
#
# This is a POSIX shell fragment
#
# On what interfaces showld the DHCP server (dhcpd) serve DHCP requests?
# Separate multiple interfaces with spaces, e.g. "eh0 eth1".
INTERFACES="eth2"

Ahora procedemos a modificar el archivo «/etc/dhcp/dhcpd.conf«, en «max-lease-time» lo definimos a «43200» ya que el tiempo de concesión deseado es de 12 horas:

ddns-update-style none;

default-lease-time 600;
max-lease-time 43200;

authoritative;
log-facility local7;

option subnet-mask 255.255.255.0;
option broadcast-address 192.168.100.255;
option routers 192.168.100.1;
option domain-name-servers 192.168.100.1;
option domain-name "servidor.internal";

subnet 192.168.100.0 netmask 255.255.255.0 {
 range 192.168.100.2 192.168.100.253;
}

Reiniciamos el servicio:

root@Servidor:/home/vagrant# service isc-dhcp-server restart

Reiniciamos el servicio de red en la máquina cliente «nodo_lan1» y comprobamos la ip que ha obtenido la interfaz:

eth1 Link encap:Ethernet HWaddr 08:00:27:6d:a7:38 
 inet addr:192.168.100.2 Bcast:192.168.100.255 Mask:255.255.255.0
 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
 RX packets:82 errors:0 dropped:0 overruns:0 frame:0
 TX packets:84 errors:0 dropped:0 overruns:0 carrier:0
 collisions:0 txqueuelen:1000 
 RX bytes:16486 (16.4 KB) TX bytes:16056 (16.0 KB)

Observamos que ha obtenido la ip «192.168.100.2».

Con el comando «tail /var/lib/dhcp/dhcpd.lease obtenemos la lista de direcciones ip proporcionadas:

root@Servidor:/home/vagrant# tail /var/lib/dhcp/dhcpd.leases
 }
 lease 192.168.100.2 {
 starts 1 2014/09/29 11:39:59;
 ends 1 2014/09/29 11:49:59;
 cltt 1 2014/09/29 11:39:59;
 binding state active;
 next binding state free;
 hardware ethernet 08:00:27:6d:a7:38;
 client-hostname "NodoLan1";
 }

Vemos como se ha proporcionado la ip «192.168.100.2»  al cliente con nombre «nodolan1» y con dirección MAC «08:00:27:6d:a7:38»

Configuramos el servidor para que funcione como router, para ello activamos el bit de enrutamiento en el archivo «/etc/sysctl.conf«

# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1

Ahora modificamos el archivo «/etc/network/interfaces» y añadimos la siguiente linea para configurar NAT en nuestro servidor:

up iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o eth1 -j MASQUERADE

Reiniciamos el servicio de red, «/etc/init.d/networking restart«

Para que esto funcione debemos borrar las rutas por defecto que traen nuestras máquinas (servidor y cliente) y configurar nuevas entradas por defecto con la ip e interfaz que deseamos.

En el servidor:

route add default gw 192.168.1.1 dev eth1

En el cliente:

route add default gw 192.168.100.1 dev eth1

Hacemos ping desde el cliente a «www.google.es»:

root@NodoLan1:/home/vagrant# ping www.google.es
PING www.google.es (74.125.230.248) 56(84) bytes of data.
64 bytes from par08s10-in-f24.1e100.net (74.125.230.248): icmp_req=1 ttl=52 time=47.1 ms
64 bytes from lhr08s06-in-f24.1e100.net (74.125.230.248): icmp_req=2 ttl=52 time=44.5 ms
64 bytes from lhr08s06-in-f24.1e100.net (74.125.230.248): icmp_req=3 ttl=52 time=46.1 ms

Como vemos, el cliente tiene conexión a internet.

Realizamos una captura «tcpdump» en el cliente y pedimos una nueva concesión de ip con «dhclient eth1« :

root@NodoLan1:/home/vagrant# tcpdump -i eth1 port 67 or port 68 
tcpdump: WARNING: eth1: no IPv4 address assigned tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth1, 
link-type EN10MB (Ethernet), capture size 65535 bytes 

15:43:58.309140 IP 0.0.0.0.bootpc > 255.255.255.255.bootps: BOOTP/DHCP, Request from 08:00:27:6d:a7:38 (oui Unknown), length 300 
15:43:58.309742 IP 192.168.100.1.bootps > 192.168.100.2.bootpc: BOOTP/DHCP, Reply, length 300 
15:43:58.309979 IP 0.0.0.0.bootpc > 255.255.255.255.bootps: BOOTP/DHCP, Request from 08:00:27:6d:a7:38 (oui Unknown), length 300 
15:43:58.312470 IP 192.168.100.1.bootps > 192.168.100.2.bootpc: BOOTP/DHCP, Reply, length 300
  • Primer mensaje capturado:  se realiza una petición «dhcp discover» en la que la interfaz envía esta petición buscando algún servidor dhcp.
  • Segundo mensaje: vemos la respuesta del servidor dhcp por lo que este mensaje es «dhcp offer«.
  • Tercer mensaje: se realiza «dhcp requests» que es la respuesta de nuestro cliente al servidor.
  • Cuarto mensaje: obtenemos el paquete «dhcp ack» en el que se realiza la concesión IP al cliente.

Funcionamiento del dhcp

Procedemos a modificar el archivo «/etc/dhcp/dhcpd.conf» y en  «max-lease-time» lo definimos a «20«. Ahora tenemos un tiempo de concesión bajo.

Paramos el servicio dhcp y pasado el tiempo de concesión nuestro cliente pierde su ip:

eth1 Link encap:Ethernet HWaddr 08:00:27:6d:a7:38 
 inet6 addr: fe80::a00:27ff:fe6d:a738/64 Scope:Link
 UP BROADCAST RUNNING PROMISC MULTICAST MTU:1500 Metric:1
 RX packets:395 errors:0 dropped:0 overruns:0 frame:0
 TX packets:309 errors:0 dropped:0 overruns:0 carrier:0
 collisions:0 txqueuelen:1000 
 RX bytes:59256 (59.2 KB) TX bytes:49330 (49.3 KB)

Modificamos de nuevo el archivo y cambiamos el rango ip de concesión, de tal forma que quede así:

ddns-update-style none;
default-lease-time 600;
max-lease-time 10;
authoritative;
log-facility local7;
option subnet-mask 255.255.255.0;
option broadcast-address 192.168.100.255;
option routers 192.168.100.1;
option domain-name-servers 192.168.100.1;
option domain-name "servidor.internal";
subnet 192.168.100.0 netmask 255.255.255.0 {
 range 192.168.100.50 192.168.100.253;
}

Reiniciamos el servicio y pasado el tiempo de concesión la nueva ip del cliente es la siguiente:

eth1 Link encap:Ethernet HWaddr 08:00:27:9a:0d:6f 
 inet addr:192.168.100.50 Bcast:192.168.100.255 Mask:255.255.255.0
 inet6 addr: fe80::a00:27ff:fe9a:d6f/64 Scope:Link
 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
 RX packets:74 errors:0 dropped:0 overruns:0 frame:0
 TX packets:122 errors:0 dropped:0 overruns:0 carrier:0
 collisions:0 txqueuelen:1000 
 RX bytes:16884 (16.8 KB) TX bytes:30132 (30.1 KB)

Configuración reservas IP

Crea una reserva para el que el cliente tome siempre la dirección 192.168.100.100.

 Añadimos al fichero «/etc/dhcp/dhcpd.conf» lo siguiente para realizar una reserva ip a nuestro cliente nodolan:
host nodolan {
hardware ethernet 08:00:27:9a:0d:6f;
fixed-address 192.168.100.100;
}

Reiniciamos el servicio y pasado el tiempo de concesión la nueva ip del cliente es la reservada :

eth1 Link encap:Ethernet HWaddr 08:00:27:9a:0d:6f 
 inet addr:192.168.100.100 Bcast:192.168.100.255 Mask:255.255.255.0
 inet6 addr: fe80::a00:27ff:fe9a:d6f/64 Scope:Link
 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
 RX packets:157 errors:0 dropped:0 overruns:0 frame:0
 TX packets:205 errors:0 dropped:0 overruns:0 carrier:0
 collisions:0 txqueuelen:1000 
 RX bytes:38784 (38.7 KB) TX bytes:51618 (51.6 KB)

Uso de varios ámbitos

Modifica el escenario Vagrant para añadir una nueva red local y un nuevo nodo:

  • Servidor: En el servidor hay que crear una nueva interfaz

  • nodo_lan2: Un cliente conectado a la segunda red local.

Configura el servidor dhcp en el ordenador “servidor” para que de servicio a los ordenadores de la nueva red local, teniendo en cuante que el tiempo de concesión sea 24 horas y que la red local tiene el direccionamiento 192.168.200.0/24.

Modificamos el fichero Vagrantfile y añadimos una nueva interfaz en «servidor1» y añadimos un nuevo nodo, el fichero quedará de la siguiente forma:

# -*- mode: ruby -*-
# vi: set ft=ruby :

VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

  config.vm.define :servidor1 do |servidor1|
    servidor1.vm.box = "precise64"
    servidor1.vm.hostname = "Servidor1"
    servidor1.vm.network "public_network",:bridge=>"eth0"
    servidor1.vm.network "private_network", ip: "192.168.100.1",
      virtualbox__intnet: "redinterna"
    servidor1.vm.network "private_network", ip: "192.168.200.1",
      virtualbox__intnet: "redinterna2"
  end
  config.vm.define :nodolan1 do |nodolan1|
    nodolan1.vm.box = "precise64"
    nodolan1.vm.hostname = "NodoLan"
    nodolan1.vm.network "private_network", type: "dhcp",
      virtualbox__intnet: "redinterna"
  end
  config.vm.define :nodolan2 do |nodolan2|
    nodolan2.vm.box = "precise64"
    nodolan2.vm.hostname = "NodoLan2"
    nodolan2.vm.network "private_network", type: "dhcp",
      virtualbox__intnet: "redinterna2"
  end
end

Iniciamos las máquinas y en el servidor modificamos el archivo «/etc/default/isc-dhcp-server»  en el que añadiremos la nueva interfaz:

GNU nano 2.2.6 File: /etc/default/isc-dhcp-server
# Defaults for dhcp initscript
 # sourced by /etc/init.d/dhcp
 # installed at /etc/default/isc-dhcp-server by the maintainer scripts
 #
 # This is a POSIX shell fragment
 #
 # On what interfaces showld the DHCP server (dhcpd) serve DHCP requests?
 # Separate multiple interfaces with spaces, e.g. "eh0 eth1".
 INTERFACES="eth2 eth3"

Ahora procedemos a modificar el archivo /etc/dhcp/dhcpd.conf”, “max-lease-time” lo definimos a “43200” ya que el tiempo de concesión deseado es de 12 horas y añadimos lo siguiente:

option subnet-mask 255.255.255.0;
option broadcast-address 192.168.200.255;
option routers 192.168.200.1;
option domain-name-servers 192.168.200.1;
option domain-name "servidor.internal2";

subnet 192.168.200.0 netmask 255.255.255.0 {
range 192.168.200.2 192.168.200.253;
}

El fichero quedará así:

ddns-update-style none;

default-lease-time 600;
 max-lease-time 43200;

authoritative;
 log-facility local7;

option subnet-mask 255.255.255.0;
 option broadcast-address 192.168.100.255;
 option routers 192.168.100.1;
 option domain-name-servers 192.168.100.1;
 option domain-name "servidor.internal";

subnet 192.168.100.0 netmask 255.255.255.0 {
 range 192.168.100.2 192.168.100.253;
 }
host nodolan {
 hardware ethernet 08:00:27:9a:0d:6f;
 fixed-address 192.168.100.100;
 }
option subnet-mask 255.255.255.0;
 option broadcast-address 192.168.200.255;
 option routers 192.168.200.1;
 option domain-name-servers 192.168.200.1;
 option domain-name "servidor.internal2";
subnet 192.168.200.0 netmask 255.255.255.0 {
 range 192.168.200.2 192.168.200.253;
 }

Reiniciamos el servicio dhcp en el servidor y realizamos en el cliente 2 una petición dhcp en la que obtendremos la siguiente ip:

eth1 Link encap:Ethernet HWaddr 08:00:27:9a:fb:98 
 inet addr:192.168.200.2 Bcast:192.168.200.255 Mask:255.255.255.0
 inet6 addr: fe80::a00:27ff:fe9a:fb98/64 Scope:Link
 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
 RX packets:13 errors:0 dropped:0 overruns:0 frame:0
 TX packets:17 errors:0 dropped:0 overruns:0 carrier:0
 collisions:0 txqueuelen:1000 
 RX bytes:2756 (2.7 KB) TX bytes:3050 (3.0 KB)

Creación de script

Realiza un script en python que de información de las concesiones del servidor:

infodhcp.py -l: Nos muestra todas las ips que están concedidas (las reservas también). Nos da información de los dos ámbitos. infodhcp.py x.x.x.x : Nos dice si esa ip está concedida y a que MAC corresponde.

Podeís ver el script que realicé para el ejercicio en mi sitio de github.

https://github.com/ManuelLunaPerez/ServiciosSGS/blob/master/infodhcp.py

Deja un comentario