Como configurar um servidor de DNS Dinâmico com o Bind 9.x

O processo de configuração do bind para aceitar atualizações dinâmicas é bem simples de ser feito, os passos abaixo podem ser executados em um FreeBSD 8.0 “out of the box” que já traz no sistema base o Bind , mas a configuração é semelhante em outros sistemas operacionais.

Para facilitar os exemplos vamos considerar os seguintes dados para o nosso Servidor de DNS:

IP do servidor Primário de DNS:      192.168.192.100
IP do servidor Secundário de DNS: 192.168.192.101
Dominio: fugspbr.org

Vejamos o passo a passo para a configuração

1.o Passo: Criar o arquivo de seed para o named

Para isso vamos criar o arquivo /etc/namedb/zones/fugspbr.org.hosts com o seguinte conteudo:

$ORIGIN .
$TTL 300       ;
fugspbr.org.    IN      SOA     ns01.fugspbr.org.       hostmaster.fugspbr.org. (
                                2501201001 ;
                                300        ;
                                300        ;
                                300        ;
                                300        ;
                                )
fugspbr.org.         IN      NS      ns01.fugspbr.org.
fugspbr.org.         IN      NS      ns02.fugspbr.org.
ns01.fugspbr.org.    IN      A       192.168.192.100
ns02.fugspbr.org.    IN      A       192.168.192.101

2.o Passo: Gerar a chave de criptografia

A criação da chave de criptografia é feita com através do comando dnssec-keygen, e a chave publica e privada é gerada no diretório no qual o comando foi executado. Sugiro armazená-las num diretório separado dentro da area de configuração do named, como por exemplo no diretório /etc/namedb/zones/keys.

A sintaxe é bem simples, basta executar:

# dnssec-keygen -b 512 -a HMAC-MD5 -v 2 -n HOST fugspbr.org.
Kfugspbr.org.+157+45086
# ls -l
-rw-------  1 root  wheel  120 Jan 24 11:05 Kfugspbr.org.+157+45086.key
-rw-------  1 root  wheel  156 Jan 24 11:05 Kfugspbr.org.+157+45086.private

Ao ser executado o dnssec-keygen gerou 2 arquivos, um com a extensão .key e outro com a extensão .private. Vamos precisar da chave de criptografia na próxima etapa, ela está destacada abaixo na cor verde:

# cat Kfugspbr.org.+157+45086.private
Private-key-format: v1.2
Algorithm: 157 (HMAC_MD5)
Key: vG4tx7SVi1YKXMn+2ig4dQ+pejRpNmRNCpWcyTfTXfIThXHc7YDrOMJUlRypXIqe8aqtJJr0PuA9tjxlvfxqnA==
Bits: AAA=

Obs: é óbvio, mas não custa reforçar, o hash acima não é o que eu uso no meu servidor real de DNS ;)

3.o Passo: Configurar o named

O arquivo de configuração do named no FreeBSD é o /etc/namedb/named.conf, não se preocupe com o numero de linhas abaixo pois o arquivo está completo, a configuração em si necessária para habilitar as atualizações dinâmicas é bem simples e está destacada em vermelho e em verde:

// /etc/namedb/named.conf
// ACLs

acl "xfer" {
    192.168.192.101;
    };

acl "trusted" {
    127.0.0.1;
    };

// Opcoes do named

options {
    directory       "/etc/namedb";
    pid-file        "/var/run/named/pid";
    dump-file       "/var/dump/named_dump.db";
    statistics-file "/var/stats/named.stats";
    notify no;
    listen-on port 53 { 192.168.192.100; 127.0.0.1; };
    zone-statistics yes;
    transfer-format many-answers;
    max-transfer-time-in 60;
    interface-interval 0;
    allow-transfer { xfer; };
    allow-query { trusted; };
};

// Controle da atualização dinamica

key fugspbr.org. {
        algorithm "HMAC-MD5";
        secret "vG4tx7SVi1YKXMn+2ig4dQ+pejRpNmRNCpWcyTfTXfIThXHc7YDrOMJUlRypXIqe8aqtJJr0PuA9tjxlvfxqnA==";
};

// Visao interna - Permite queries recursivas se feitas pelo proprio server

view "internal-in" in {
    match-clients { trusted; };
    recursion yes;
    additional-from-auth yes;
    additional-from-cache yes;

};

// Visao Externa - Nao permite queries recursivas

view "external-in" in {
    match-clients { any; };
    recursion no;
    additional-from-auth no;
    additional-from-cache no;

zone "fugspbr.org" {
        type master;
        file "zones/fugspbr.org.hosts";
        allow-update{
                key fugspbr.org;
        };
        notify yes;
        also-notify { 192.168.192.101; };
        allow-query { any; };
        };
};

// Visao Caos - Nao permite queries por "."

view "external-chaos" chaos {
    match-clients { any; };
    recursion no;
          zone "." {
              type hint;
              file "/dev/null";
          };
};

// FIM DO ARQUIVO

Vocês podem perceber que usei algumas ACLs na configuração acima, costumo usá-las para evitar que pessoas não autorizadas realizem consultas recursivas no meu servidor de DNS.

Normalmente trabalho com uma view interna a qual permite consultas recursivas do próprio servidor, uma view externa a qual só permite consultas aos dominios para os quais o servidor é autoritativo, e uma view caos que trata as requisições de resolução para os root servers (consultas por “.”).

Por razões óbvias se você precisar usar o seu servidor para resolver outros dominios de forma recursiva você vai precisar alterar as ACLs, observe que as requisições do nsupdate estão sujeitas as mesmas regras que uma query normal, pelas regras acima a requisição do nsupdate tem que cair no view “external-in” para que a atualização funcione uma vez que é a view na qual declaramos a zona fugspbr.org .

Como eu defini o ip 127.0.0.1 na ACL trusted e esta ACL dá match no view “internal-in”, você deverá especificar o IP publico do seu servidor (no nosso exemplo o 192.168.192.100)  na hora de usar o nsupdate, se usar localhost como server, você terá como resultado uma falha de autenticação.

Se você não quizer se preocupar com regras de ACL (ou não precisar controlar o acesso das consultas recursivas ao seu servidor), você pode usar como configuração o arquivo abaixo:

// Arquivo /etc;namedb/named.conf
// Opcoes do Bind

options {
    directory       "/etc/namedb";
    pid-file        "/var/run/named/pid";
    dump-file       "/var/dump/named_dump.db";
    statistics-file "/var/stats/named.stats";
    notify no;
    listen-on port 53 { 192.168.192.100; 127.0.0.1; };
    zone-statistics yes;
    transfer-format many-answers;
    max-transfer-time-in 60;
    interface-interval 0;
    allow-transfer { 192.168.192.101; };
    allow-query { any; };
};

// Controles

key fugspbr.org {
        algorithm "HMAC-MD5";
        secret "vG4tx7SVi1YKXMn+2ig4dQ+pejRpNmRNCpWcyTfTXfIThXHc7YDrOMJUlRypXIqe8aqtJJr0PuA9tjxlvfxqnA==";
};

// Zonas

zone "fugspbr.org" {
        type master;
        file "zones/fugspbr.org.hosts";
        allow-update{
                key fugspbr.org;
        };
        notify yes;
        also-notify { 192.168.192.101; };
        allow-query { any; };
        };

// FIM

Ao subir o servidor com esta configuração ele irá responder a todas as requisições recursivas que receber independente da origem das mesmas, o que pode ser bom ou ruim dependendo da situação ;)

Lembre-se de verificar se o usuário através do qual você executa o named (normalmente é o usuário/grupo chamado bind) tem permissão de escrita no diretório /etc/namedb/zones , se ele não tiver permissão de escrita o named não vai conseguir gerar o arquivo de journal  (fugspbr.org.hosts.jnl) e a atualização dinâmica não vai funcionar.

4.o Passo: Habilitar o named no /etc/rc.conf

Para que o named seja iniciado quando seu servidor FreeBSD for iniciado, você deve adicionar a seguinte linha ao seu arquivo /etc/rc.conf:

named_enable="YES"

Para inciá-lo manualmente basta executar o comando:

# /etc/rc.d/named start

5.o Passo: Testar se o named está resolvendo seu dominio

A maneira mais simples de testar o seu servidor é através do aplicativo dig, para isso basta executar o comando abaixo:

# dig @192.168.192.100 ns01.fugspbr.org

; <<>> DiG 9.6.1-P1 <<>> @192.168.192.100 ns01.fugspbr.org
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 45187
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;ns01.fugspbr.org.              IN      A

;; ANSWER SECTION:
ns01.fugspbr.org.       300     IN      A       192.168.192.100

;; AUTHORITY SECTION:
fugspbr.org.            300     IN      NS      ns01.fugspbr.org.
fugspbr.org.            300     IN      NS      ns02.fugspbr.org.

;; ADDITIONAL SECTION:
ns02.fugspbr.org.       300     IN      A       192.168.192.101

;; Query time: 3 msec
;; SERVER: 192.168.192.100#53(192.168.192.100)
;; WHEN: Sun Jan 24 12:13:13 2010
;; MSG SIZE  rcvd: 99

Como podem ver o servidor está respondendo corretamente pelo dominio fugspbr.org.

6.o Passo: Testar a atualização dinâmica

A atualização dinâmica de uma zona DNS no named é feita através do comando nsupdate.
Como o arquivo de seed que usamos no setup inicial não possuia nenhuma entrada de host além das entradas para ns01.fugspbr.org e ns02.fugspbr.org, se fizermos uma consulta por exemplo por www.fugspbr.org teremos a seguinte resposta:

# dig @192.168.192.100 www.fugspbr.org

; <<>> DiG 9.6.1-P1 <<>> @192.168.192.100 www.fugspbr.org
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 5139
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;www.fugspbr.org.               IN      A

;; AUTHORITY SECTION:
fugspbr.org.            300     IN      SOA     ns01.fugspbr.org. hostmaster.fugspbr.org. 2501201003 300 300 300 300

;; Query time: 0 msec
;; SERVER: 192.168.192.100#53(192.168.192.100)
;; WHEN: Sun Jan 24 11:50:41 2010
;; MSG SIZE  rcvd: 85

Vejam que a resposta do dig não exibe uma “ANSWER SECTION” , para criarmos de forma dinâmica uma entrada para www.fugspbr.org apontando por exemplo para o ip 192.168.192.103, devemos usar a seguinte sintaxe no nsupdate:

# nsupdate -k /etc/namedb/zones/keys/Kfugspbr.org.+157+45086.private
> server 192.168.192.100
> update add www.fugspbr.org 3600 A 192.168.192.103
> show
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:      0
;; flags: ; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
;; UPDATE SECTION:
www.fugspbr.org.        3600    IN      A       192.168.192.103
> send
> quit
#

Agora se repetirmos a consulta que fizemos inicialmente veremos que já vai aparecer o host que criamos (destacado em azul) :

# dig @192.168.192.100 www.fugspbr.org

; <<>> DiG 9.6.1-P1 <<>> @localhost192.168.192.100 www.fugspbr.org
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34467
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 2
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;www.fugspbr.org.               IN      A

;; ANSWER SECTION:
www.fugspbr.org.        3600    IN      A       192.168.192.103

;; AUTHORITY SECTION:
fugspbr.org.            300     IN      NS      ns02.fugspbr.org.
fugspbr.org.            300     IN      NS      ns01.fugspbr.org.

;; ADDITIONAL SECTION:
ns01.fugspbr.org.       300     IN      A       192.168.192.100
ns02.fugspbr.org.       300     IN      A       192.168.192.101

;; Query time: 10 msec
;; SERVER: 127.0.0.192.168.192.100#53(192.168.192.100)
;; WHEN: Sun Jan 24 11:49:06 2010
;; MSG SIZE  rcvd: 119
#

Uma vez que o seu servidor de DNS está configurado para aceitar atualizações dinâmicas com o nsupdate, vamos dar uma olhada num script simples para simplificar o processo de update.

7.o Passo: Exemplo de shell script para atualização de um registro no DNS

Lembre-se que existem infinitas formas de criar um script para interagir com o nsupdate, abaixo coloquei o código de um shell script que eu fiz a muito tempo atrás para atualizar meu DNS com IP dinâmico do meu box FreeBSD aqui de casa, no meu caso o IP publico fica no meu roteador e o servidor tem um ip inválido, eu executo este script no boot do FreeBSD, e depois a cada 15 minutos via cron.

Para pegar o IP publico da minha conexão o script acessa um script php que eu hospedei no servidor onde rodo o blog, o qual retorna como resultado o REMOTE_ADDR da pessoa que fez a requisição http.

----- Corte aqui -----
#!/bin/sh

# Definicao de variaveis -- Customize!!!

key="fugspbr.org"
secret="vG4tx7SVi1YKXMn+2ig4dQ+pejRpNmRNCpWcyTfTXfIThXHc7YDrOMJUlRypXIqe8aqtJJr0PuA9tjxlvfxqnA=="
servidor="ns01.fugspbr.org"
zona="fugspbr.org"
host="$1.fugspbr.org"
ttl="300"

case $2 in
  add)
  # Obtem ip externo
  ip="`/usr/local/bin/lynx -dump http://blog.ebrandi.eti.br/meuip.php | /usr/bin/head -1 | /usr/bin/awk -F" " '{print $1}'`"

  # Banner
  /bin/echo
  /bin/echo "Atualizando registro $host para o ip $ip"
  /bin/echo
  /bin/echo "#############################################################"
  /bin/echo

  # Prepara o update
  /bin/echo "server $servidor" > /tmp/nsupdate.tmp
  /bin/echo "key $key $secret" >> /tmp/nsupdate.tmp
  /bin/echo "zone $zona" >> /tmp/nsupdate.tmp
  /bin/echo "update delete $host A" >> /tmp/nsupdate.tmp
  /bin/echo "update add $host $ttl A $ip" >> /tmp/nsupdate.tmp
  /bin/echo "show" >> /tmp/nsupdate.tmp
  /bin/echo "send" >> /tmp/nsupdate.tmp
  /bin/echo "quit" >> /tmp/nsupdate.tmp

  # Executa update #
  /bin/cat /tmp/nsupdate.tmp | /usr/bin/nsupdate

  /bin/echo "#############################################################"
  /bin/echo

  # remove arquivo temporario
  /bin/rm /tmp/nsupdate.tmp
  ;;

del)
  # Banner
  /bin/echo
  /bin/echo "Removendo o registro $host"
  /bin/echo
  /bin/echo "#############################################################"
  /bin/echo

  # Prepara update #
  /bin/echo "server $servidor" > /tmp/nsupdate.tmp
  /bin/echo "key $key $secret" >> /tmp/nsupdate.tmp
  /bin/echo "zone $zona" >> /tmp/nsupdate.tmp
  /bin/echo "update delete $host A" >> /tmp/nsupdate.tmp
  /bin/echo "show" >> /tmp/nsupdate.tmp
  /bin/echo "send" >> /tmp/nsupdate.tmp
  /bin/echo "quit" >> /tmp/nsupdate.tmp

  # Executa update #
  /bin/cat /tmp/nsupdate.tmp | /usr/bin/nsupdate

  /bin/echo "#############################################################"
  /bin/echo

  # remove arquivo temporario
  /bin/rm /tmp/nsupdate.tmp
  ;;
esac
----- corte aqui -----

Para usá-lo é muito simples, o script aceita apenas 2 parametros na linha de comando, o primeiro deve ser nome do host desejado, e o segundo é a ação desejada (add ou del), vejam um exemplo:

% ./update ftp add

Atualizando registro ftp.fugspbr.org para o ip 201.6.215.146

#############################################################

Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:      0
;; flags: ; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
;; ZONE SECTION:
;fugspbr.org.                   IN      SOA

;; UPDATE SECTION:
ftp.fugspbr.org.        0       ANY     A
ftp.fugspbr.org.        300     IN      A       201.6.215.146

#############################################################

% dig @192.168.192.100 ftp.fugspbr.org

; <<>> DiG 9.6.1-P1 <<>> @192.168.192.100 ftp.fugspbr.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51116
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 2
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;ftp.fugspbr.org.               IN      A

;; ANSWER SECTION:
ftp.fugspbr.org.        300     IN      A       201.6.215.146

;; AUTHORITY SECTION:
fugspbr.org.            300     IN      NS      ns02.fugspbr.org.
fugspbr.org.            300     IN      NS      ns01.fugspbr.org.

;; ADDITIONAL SECTION:
ns01.fugspbr.org.       300     IN      A       192.168.192.100
ns02.fugspbr.org.       300     IN      A       192.168.192.101

;; Query time: 0 msec
;; SERVER: 192.168.75.130#53(192.168.192.100)
;; WHEN: Sun Jan 24 17:53:06 2010
;; MSG SIZE  rcvd: 119

Para remover o registro que foi criado basta executar com o parametro del:

% ./update ftp del

Removendo o registro ftp.fugspbr.org

#############################################################

Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:      0
;; flags: ; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
;; ZONE SECTION:
;fugspbr.org.                   IN      SOA

;; UPDATE SECTION:
ftp.fugspbr.org.        0       ANY     A

#############################################################

% dig @192.168.192.100 ftp.fugspbr.org

; <<>> DiG 9.6.1-P1 <<>> @192.168.192.100 ftp.fugspbr.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 20920
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;ftp.fugspbr.org.               IN      A

;; AUTHORITY SECTION:
fugspbr.org.            300     IN      SOA     ns01.fugspbr.org. hostmaster.fugspbr.org. 2501201029 300 300 300 300

;; Query time: 0 msec
;; SERVER: 192.168.192.100#53(192.168.192.100)
;; WHEN: Sun Jan 24 17:56:25 2010
;; MSG SIZE  rcvd: 85

Como comentei antes, o script acima é só um exemplo de como automatizar a atualização, no meu caso não tenho problemas em atualizar o registro do host mesmo que o IP não tenha sido alterado, mas outras pessoas podem ter problema com isso…o script pode ser alterado facilmente para só fazer a atualização do DNS se for detectada uma alteração do IP externo, não é nada que um “if” e um arquivo temporário de apoio não resolvam ;)

Bom divertimento

[]´s Edson

One Response to “Como configurar um servidor de DNS Dinâmico com o Bind 9.x”

  1. [New Post] Como configurar um servidor de DNS Dinâmico com o Bind 9.x – http://blog.ebrandi.eti.br/2010/01/como-