Configuración de un nombre de dominio

Se le asignará al equipo el nombre de dominio cactus.rufian.eu.

Hay un equipo en Internet (el cual administro) que es SOA (Start of Authority) del dominio rufian.eu. Aprovechando esto, registraré cactus.rufian.eu como un subdominio.

Configuración de un subdominio

He de acudir a la configuración de mi servidor DNS, bind9.

bind9 define unos archivos de zona donde se especifican la información de un determinado dominio, así como los subdominios que posee.

Localizo el archivo de zona de rufian.eu y añado la siguiente línea:

cactus      A       x.x.x.x

Donde x.x.x.x es la dirección IP pública de la red donde está instalado Cactus.

Reinicio bind y ya tengo un nombre de dominio con el que acceder a Cactus.

/etc/init.d/named restart

Configuración de un subdominio dinámico

Con lo escrito en el punto anterior basta para tener una configuración del dominio de Cactus apta para Internet.

Sin embargo, la situación en la que se defenderá Cactus es más dura de la situación en la que se ha desarrollado: durante la defensa Cactus no tendrá IP pública, y además no podemos saber qué IP privada tendrá hasta que lleguemos a la defensa.

Por este motivo necesitamos una manera de que Cactus se registre automáticamente en el dominio rufian.eu en el momento del arranque, con cualquiera que sea la IP que tenga. Esta técnica se denomina DDNS (Dynamic Domain Name Server), y si bien no hay muchas herramientas establecidas para llevarla acabo, con bind9 es bastante fácil de implementar.

Paso 1

Este pequeño shell script actualiza el registro A de un determinado dominio.

#!/bin/bash
[[ !( "$1" =~ ^([[:alnum:]]+\.)*[[:alnum:]]+\.?$ ) ]] && exit 1
[[ !( "$2" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$   ) ]] && exit 1

/usr/bin/nsupdate -v -k /etc/bind/rndc.key << EOF
update delete $1 A
update add $1 60 A $2
send
EOF

Nota

Para que este script funcione hay que permitir a bind9 recibir actualizaciones.

La configuración para conseguirlo suele tener una pinta como esta:

include "/etc/bind/rndc.key";
controls {
    inet 127.0.0.1 port 953 allow { 127.0.0.1/32; ::1/128; } keys { "rndc-key"; };
};

zone "rufian.eu" in {
    type master;
    file "pri/rufian.eu.zone";
    allow-query { any; };
    allow-update { localhost; };
};

/etc/bind/rndc.key contiene una clave secreta para actualizar la información de dominios. Suele generarse durante la instalación, aunque puede generarse también en cualquier momento mediante la utilidad rndc-confgen que viene instalada con bind.

En muchas distros (incluyendo Debian y Gentoo) es necesario además dar permisos de escritura a bind sobre el directorio donde está el archivo de zonas, pues inicialmente.

Para que el script pueda funcionar es necesario que sea ejecutado por un usuario que tenga permisos de lectura sobre /etc/bind/rndc.key. Normalmente este archivo pertenece al grupo bind. Una manera de ejecutarlo con permisos reducirlos es, por tanto, ejecutarlo como el usuario bind (el cual – oh, sopresa – pertenece al grupo bind).

Utilizando sudo podemos hacer que un cierto usuario pueda ejecutar este script como el usuario bind, sin darle todos los permisos de dicho grupo. Se añadirá para este fin esta línea en el archivo /etc/sudoers (el cual puede ser editado con la orden visudo).

lighttpd ALL=(named) NOPASSWD: /opt/ddns.sh

lighttpd es el nombre del usuario al que se le permitirá ejecutar el script (que he guardado en /opt/ddns.sh como el usuario named sin que se le pida contraseña para ello.

Paso 2

Teniendo el script anterior, habilito un servicio PHP que permite hacer el cambio mediante una petición HTTP. Escojo PHP porque es lo que ya tengo configurado.

<?php

$valid_keys = array(
    "Fw9qEgnzAhTtV" => array(
        "cactus.rufian.eu",
    ),
);

function reject_400($remote) {
    header("HTTP/1.1 400 Bad request");
    syslog(LOG_WARNING, "$remote: Malformed DDNS update request received.");
    exit();
}

function reject_401($remote, $key, $domain, $ip) {
    header("HTTP/1.1 401 Unauthorized");
    syslog(LOG_WARNING, "$remote: DDNS update REJECTED. key=$key domain=$domain, ip=$ip.");
    exit();
}

$remote = $_SERVER["REMOTE_ADDR"];

/* Reject if not enough parameters */
if (!isset($_GET["key"]) || !isset($_GET["domain"]) || !isset($_GET["ip"])) {
    reject_400($remote);
}

$key    = $_GET["key"];
$domain = $_GET["domain"];
$ip     = $_GET["ip"];

/* Reject strange parameters */
if ( ($key == "" || $domain == "" || $ip == "")                          ||
     (strlen($key) > 100 || strlen($domain) > 100 || strlen($ip) > 100)  ||
     (0 === preg_match('/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/', $ip))       ||
     (0 === preg_match('/^([[:alnum:]]+\.)*[[:alnum:]]+\.?$/', $domain))  )
{ reject_400($remote); }

/* Reject unauthorized keys */
if ( (!isset($valid_keys[$key]))             ||
     (!in_array($domain, $valid_keys[$key]))  )
{ reject_401($remote, $key, $domain, $ip); }

/* Accept the request */
exec('sudo -u named /opt/ddns.sh '.
     escapeshellcmd($domain).' '.
     escapeshellcmd($ip).
     ' 2>&1', $output, $return_var);

if ($return_var != 0) {
    /* Error! Print it to syslog. */
    header("HTTP/1.1 500 Internal Server Error");
    syslog(LOG_ERR, "$remote: DDNS update failed. domain=$domain, ip=$ip");
    foreach ($output as $line) {
        syslog(LOG_ERR, $line);
    }
    exit();
}

/* Return OK */
syslog(LOG_NOTICE, "$remote: DDNS update. domain=$domain, ip=$ip");
echo("OK"); ?>

Nota

Las claves que aparecen en la documentación son muestras representativas, y no coinciden con las claves realmente usadas en Cactus o en otros servidores.

Habilito también otro pequeño servicio para obtener la IP pública de un equipo.

<?php echo($_SERVER["REMOTE_ADDR"]); ?>

Paso 3

Por último hay que configurar el servidor Cactus para que al conectarse a la red registre su dirección IP en el servidor DNS.

Para esto creo un script en /etc/network/if-up.d/rufian-ddns.

#!/bin/bash
export SSL_CERT_DIR=/etc/ssl/certs

USE_PUBLIC_IP=true
DOMAIN=cactus.rufian.eu
KEY=Fw9qEgnzAhTtV

if $USE_PUBLIC_IP
then
    IP=`wget -q -O - "https://ssl.rufian.eu/checkip.php"`
else
    IP=`hostname -I`
fi

wget -q -O - "https://ssl.rufian.eu/ddns.php?key=${KEY}&domain=${DOMAIN}&ip=${IP}"

Nota

Para que wget no arroje errores de certificado inválido es necesario instalar los certificados de las autoridades raíz.

aptitude install ca-certificates

Y le doy permisos de ejecución.

chmod +x /etc/network/if-up.d/rufian-ddns

El script tiene una variable USE_PUBLIC_IP que permite establecer si queremos que se registre en el DNS con su IP pública (true) o con su IP privada (false). Durante el desarrollo de Cactus nos interesa que esté a true para poder trabajar con él a través de Internet. La versión entregable, no obstante, se probará en una red local, por lo que esta variable se establecerá a false antes de la entrega.

Contenidos

Tema anterior

Configuración inicial

Próximo tema

Instalación de un certificado TLS

Esta página