DHCP (sigla en inglés de Dynamic Host Configuration Protocol) es un protocolo de red que permite a los nodos de una red IP obtener sus parámetros de configuración automáticamente. Se trata de un protocolo de tipo cliente/servidor en el que generalmente un servidor posee una lista de direcciones IP dinámicas y las va asignando a los clientes conforme éstas van estando libres, sabiendo en todo momento quién ha estado en posesión de esa IP, cuánto tiempo la ha tenido y a quién se la ha asignado después.
Veremos como configurar un servidor DHCP con alta disponibilidad y configuracion replicada por medio de Cscync2
Para el esquema distribuido de configuracion DHCP tuvieron que modificarse parámetros de configuración de dicho servicio.
En la directiva wpad: se utilizo un nombre para indicar la ubicación del archivo de autoconfiguración del proxy, y en cada red dicha entrada DNS puede variar.
La configuracion de subredes y de hosts fijos se separo en diferentes archivos para una mejor edición por parte de los administradores
Configuracion
authoritative; option netbios-name-servers 10.1.203.32; option wpad code 252 = text; option wpad "http://proxyconf.cayu.com.ar/proxy.pac"; ddns-update-style none; #CONFIGURACION DE ALTA DISPONIBILIDAD include "/etc/dhcpd.peer"; include "/etc/dhcp/ba.conf"; include "/etc/dhcp/ba_hosts.conf";
failover peer "dhcp" { secondary; address 10.1.100.10; port 519; peer address 10.1.100.11; peer port 519; max-response-delay 60; max-unacked-updates 10; load balance max seconds 3; }
function FindProxyForURL(url, host){ if(dnsDomainIs(host, "cayu.com.ar")) return "DIRECT"; if(dnsDomainIs(host, "sergiocayuqueo.com.ar")) return "DIRECT"; if(shExpMatch(host, "intranet*")) return "DIRECT"; if(isInNet(host, "1.1.0.0", "255.255.0.0")) return "DIRECT"; if(isInNet(host, "149.194.0.0", "255.255.0.0")) return "DIRECT"; if(isInNet(host, "192.168.0.0", "255.255.0.0")) return "DIRECT"; if(isInNet(host, "10.0.0.0", "255.0.0.0")) return "DIRECT"; if(isInNet(host, "10.199.0.0", "255.255.0.0")) return "DIRECT"; if(isInNet(myIpAddress(), "10.90.0.0", "255.224.0.0")) return "PROXY proxybuenosiares.cayu.com.ar:8080"; if(isInNet(myIpAddress(), "10.22.0.0", "255.255.0.0")) return "PROXY proxyfvarela.cayu.com.ar:8080"; if(isInNet(myIpAddress(), "10.23.0.0", "255.255.0.0")) return "PROXY proxyquilmes.cayu.com.ar:8080"; return "PROXY proxybuenosaires.cayu.com.ar:8080"; }
Segun desde que red nos conectemos nos asigna un proxy diferente
MENSAJES DE LOG
Mensaje | Quien lo envia | Descripcion | ||
---|---|---|---|---|
DHCPDISCOVER | Cliente | Envía un mensaje de difusión para localizar a los servidores DHCP activos | ||
DHCPOFFER | Servidor | Responde con una oferta de parámetros de configuración conforme a la situación del cliente | ||
DHCPREQUEST | Cliente | Solicita los parámetros ofrecidos, en caso de que el mensaje del servidor haya sido aceptado, rechazando la oferta, si el mensaje del servidor ha sido desestimado o confirmando la solicitud de una dirección IP obtenida anteriormente | ||
DHCPACK | Servidor | Mensaje de confirmación y cierre, indicando los parámetros definitivos | ||
DHCPNACK | Servidor | Informe de que la dirección IP que solicita no es válida para la subred en la que se encuentra o ya no la puede asignar porque la tiene otro equipo. | ||
DHCPDECLINE | Cliente | Informe de que la dirección está en uso, normalmente porque otro usuario ha asignado esa dirección manualmente | ||
DHCPRELEASE | Cliente | Informe de que ha finalizado el uso de la dirección IP | ||
DHCPINFORM | Cliente | Consulta sobre la configuración local. El cliente ya está configurado cuando envía este mensaje |
Nombre | Version | Descripcion | |
---|---|---|---|
Kernel | 2.6.18-8.el5xen | Nucleo | |
RedHat | Red Hat Enterprise Linux Server release 5 | Distribucion Linux | |
System Imager | 4.0.2 | Cliente de System Imager | |
Internet Systems Consortium DHCP | 3.0.5 | Servidor de DHCP | |
nss_ldap | 253-3 | Autenticacion LDAP para PAM |
Dentro de este archivo configuraremos la disponibilidad ante fallos
Script para genera un archivo de configuracion con muchas subnets, del rango 10.216.64.0 al 10.216.98.0, con saltos de 60 a 200
authoritative; ddns-update-style interim; ignore client-updates; <?php for($i = 64; $i <= 98; $i++) { print " subnet 10.216.".$i.".0 netmask 255.255.255.0 { option subnet-mask 255.255.255.0; option domain-name-servers 10.1.200.10, 10.1.200.11; option routers 10.216.".$i.".254; option subnet-mask 255.255.255.0; max-lease-time 86400; default-lease-time 86400; pool { max-lease-time 86400; default-lease-time 86400; range 10.216.".$i.".60 10.216.".$i.".200; deny dynamic bootp clients; } } "; } ?>
Script para verificar la cantidad de leases activos expirados y abandonados
#!/usr/bin/perl # # script to list active, expired and abandoned leases. # # Original script received by Ian Jones, ltjones@hawkeye.ualr.edu # # Current Version by Rainer Krienke, krienke@uni-koblenz.de # Version 1.0 # Added: - output in local timezone # - output in HTML using -w option # - eliminate double entries for same ip address # # TL: Rework for nslu2/thttpd cgi script. # Rewrite parse to deal with ddns lines. # Break out clients & addresses. # Install in /opt/bin/leaseholders.txt # Add a script to copy to /home/httpd/html/leaseholders.cgi use Getopt::Std; use Date::Manip; use CGI; # Look for Options $res=getopts('wh'); # Echo help message if( $opt_h || $res =="" ){ die "$0 [-w] List active and expired DHCP leases \n", "\tOptions:\n", "\t -w: output is not written in HTML format.\n\n"; } $abandonedc = 0; $leasesc = 0; $expiredc = 0; # Find local host name -- from IP address if possible. $ipName = `localhost`; open(CFG, "/etc/sysconfig/network-scripts/ifcfg-ixp0"); while ($line = <CFG>) { next if ( $line =~ /^\s*#/o ); $mline = $line; chomp($mline); @wds = split( '=',$mline); next if ( $wds[0] ne "IPADDR" ); $ipAddr = $wds[1]; @numbers = split(/\./, $ipAddr); $ip_number = pack("C4", @numbers); ($ipName) = (gethostbyaddr($ip_number, 2))[0]; } close(CFG); chomp($localhost = $ipName); # # Format (see man date) in that the expiration date is echoed. # Select the format of your choice. If you want the lease time to # be printed in amarican style put a comment char ``#'' right in # front of the first $outputDateFormat line and remove it from the # second one. # # European Style date #$outputDateFormat="%H:%M:%S %d.%m.%Y "; # American style date $outputDateFormat="%m/%d/%Y %H:%M:%S"; # ### point this to your dhcpd.leases ### # /etc/dhcpd.leases and /var/state/dhcpd/dhcpd.leases # will be seachred by default. # $LEASEFILE = "/var/lib/dhcpd/dhcpd.leases"; if( ! -r $LEASEFILE ){ if( -r "/etc/dhcpd.leases" ){ $LEASEFILE="/etc/dhcpd.leases"; }else{ die "Cannot find \"dhcpd.leases\" file \n"; } } # ### get universal date from system ### # $xTZ = &ParseDate("now"); $tz=&Date_TimeZone; $x=Date_ConvTZ($xTZ, $tz, "UTC"); open(LEASES, "$LEASEFILE") or die "Can't open $LEASEFILE"; $inlease = 0; while ($line = <LEASES>) { next if( $line =~ /^\s*#/o ); $mline = $line; chomp($mline); $mline=~ s/ / /g; @wds = split( ' ',$mline); if( !$inlease ) { # Look for a lease record next if( $wds[0] ne "lease" ); $ipAddr = $wds[1]; @numbers = split(/\./, $ipAddr); $ip_number = pack("C4", @numbers); ($ipName) = (gethostbyaddr($ip_number, 2))[0]; if ($ipName) { ; } else { $ipName = "<unknown>"; } $startDt = "<unknown>"; $endDt = "<unknown>"; $endNever = 0; $ddnsClient = "<unknown>"; $ethAddr = "<unknown>"; $hostName = "<unknown>"; $leaseState = "<unknown>"; $leaseAbandoned = 0; $inlease = 1; next; } # Parse each clause in lease if( $wds[0] eq "starts" ) { $startDt = join( ' ', $wds[2], $wds[3] ); $startDt=~s/;\s*$//; # Parse Date in Date::Manip internel format $startDtUTC=ParseDate($startDt); # # Convert it to local timezone $startDtTZ=Date_ConvTZ($startDtUTC,"UTC", $tz); # # Finally make a human readable date string out of it $startDt=UnixDate($startDtTZ, ($outputDateFormat) ) ; next; } if( $wds[0] eq "ends" ) { if( $wds[2] eq "never" ) { $endDt = "2999\/01\/01 12:00:00"; $endNever = 1; } else { $endDt = join( ' ', $wds[2], $wds[3] ); $endDt=~s/;\s*$//; } # Parse Date in Date::Manip internel format $endDtUTC=ParseDate($endDt); # # Convert it to local timezone $endDtTZ=Date_ConvTZ($endDtUTC,"UTC", $tz); # # Finally make a human readable date string out of it $endDt=UnixDate($endDtTZ, ($outputDateFormat) ) ; next; } if( $wds[0] eq "hardware" ) { $ethAddr = $wds[2]; $ethAddr=~s/;\s*$//; next; } if( $wds[0] eq "client-hostname" ) { $hostName = $wds[1]; $hostName=~s/;\s*$//; $hostName=~ s/"//g; next; } if( $wds[0] eq "binding" ) { $leaseState = $wds[2]; $leaseState=~s/;\s*$//; next; } if( $wds[0] eq "set" ) { if( $wds[1] eq "ddns-client-fqdn" ) { $ddnsClient = $wds[3]; $ddnsClient=~s/"//g; } } if( $wds[0] eq "abandoned;" ) { $leaseAbandoned = 1; next; } if( $wds[0] ne "}" ) { next; } ## End of lease data, generate output $inlease = 0; if( $ipName eq "<unknown>" ) { $ipName = $ddnsClient; } $endDt = "dyn-bootp: never" if( $endNever ); $lease = sprintf "%-17s %-15s %-19s %-19s %-25s %s\n", $ethAddr, $ipAddr, $startDt, $endDt, $hostName, $ipName; $ClientLeases{$ethAddr} = $lease; $ClientLeaseTime{$ethAddr} = $endDtUTC; $ClientLeaseState{$ethAddr} = $leaseState; if( $leaseAbandoned ) { # Unexpectedly found someone with this address $AbandonedAddresses[$abandonedc++] = $lease; next; } if( $leaseState eq "active" ) { $ActiveLeases{$ipAddr} = $lease; } else { $ExpiredLease{$ipAddr} = $lease; } } close(LEASES); if( !$opt_w ){ $|=1; $q = new CGI; print $q->header('text/html'); print $q->start_html( -title=>"DHCP status on $localhost", -expires=>'+5s', -status=>'200 OK', -BGCOLOR=>'white' ); print "<PRE>\n"; } # Sort each hash & return the keys for in-order access @ClientKeys = sort(keys(%ClientLeases)); # MAC address order @ActiveKeys = sort(keys(%ActiveLeases)); # IP address order @ExpiredKeys = sort(keys(%ExpiredLeases)); # IP address order @abandoned = sort(@abandoned); # MAC, IP address (?) $xDate=UnixDate($xTZ, ($outputDateFormat) ) ; print "DHCP leases issued by $localhost as of $xDate\n"; $actc = 0; print "\nActive Clients:"; foreach $i ( @ClientKeys ) { next if( $ClientLeaseState{$i} ne "active" ); if( $actc++ == 0 ) { print "\nEthernet Address"; print " IP Address"; print " Lease Issue Time"; print " Expiration Time"; print " Client Hostname"; print " DNS Hostname\n"; print "-----------------"; print " ---------------"; print " -------------------"; print " -------------------"; print " -------------------------"; print " --------------------"; print "---------------------\n"; } print $ClientLeases{$i}; } if( $actc == 0 ) { printf " None\n"; } else { printf "Total active clients: %d\n", $actc; } $iactc = 0; print "\nInactive Clients:"; foreach $i ( @ClientKeys ) { next if( $ClientLeaseState{$i} eq "active" ); if( $iactc++ == 0 ) { print "\nEthernet Address"; print " IP Address"; print " Lease Issue Time"; print " Expiration Time"; print " Client Hostname"; print " DNS Hostname\n"; print "-----------------"; print " ---------------"; print " -------------------"; print " -------------------"; print " -------------------------"; print " --------------------"; print "---------------------\n"; } print $ClientLeases{$i}; } if( $iactc == 0 ) { printf " None\n"; } else { printf "Total inactive clients: %d\n", $iactc; } $actn = 0; print "\nActive Addresses:"; foreach $i ( @ActiveKeys ) { if( $actn++ == 0 ) { print "\nEthernet Address"; print " IP Address"; print " Lease Issue Time"; print " Expiration Time"; print " Client Hostname"; print " DNS Hostname\n"; print "-----------------"; print " ---------------"; print " -------------------"; print " -------------------"; print " -------------------------"; print " --------------------"; print "---------------------\n"; } print $ActiveLeases{$i}; } if( $actn == 0 ) { printf " None\n"; } else { printf "Total Active: %d\n", $actn; } $expn = 0; print "\nExpired Leases:"; foreach $i ( @ExpiredKeys ) { @wds = split( ' ', $ExpiredLeases{$i}); if( !defined($ActiveLeaseTime{$wds[1]}) ) { if( $expn++ == 0 ) { print "\nEthernet Address"; print " IP Address"; print " Lease Issue Time"; print " Expiration Time"; print " Client Hostname"; print " DNS Hostname\n"; print "-----------------"; print " ---------------"; print " -------------------"; print " -------------------"; print " -------------------------"; print " --------------------"; print "---------------------\n"; } print $ExpiredLeases{$i}; } } if( $expn == 0 ) { printf " None\n"; } else { printf "Total expired: %d\n", $expn; } $abdn = 0; print "\nAbandoned Addresses:"; foreach $i ( @abandoned ) { if( $abdn++ == 0 ) { print "\nEthernet Address"; print " IP Address"; print " Lease Issue Time"; print " Expiration Time"; print " Client Hostname"; print " DNS Hostname\n"; print "-----------------"; print " ---------------"; print " -------------------"; print " -------------------"; print " -------------------------"; print " --------------------"; print "---------------------\n"; } print $i; } if( $abdn == 0 ) { printf " None\n"; } else { printf "Total abandoned: %d\n", $abdn; } printf "\n"; if( !$opt_w ){ print "</PRE>\n"; $me = $q->url(); print $q->a({href=>$me},"Refresh"); print $q->br(); print $q->a({href=>"/"}, "Home Page"); print $q->end_html; } # Last line of /opt/bin/leaseholders.cgi