Como eu fiz o meu próprio serviço de DNS dinâmico
Já que os dois serviços de DNS dinâmico que eu usava estavam em condições incômodas, pensei que poderia ser divertido e útil aprender um pouco e configurar o meu próprio serviço de DNS dinâmico.
Recebi um e-mail de "Dyn" hello@dyn.com no dia 15/05/2013, com o assunto "SLA Update For Dyn Non-Paid Users", que dizia:
DNS SLA Update
Starting now, if you would like to maintain your free Dyn account, you must log into your account once a month. Failure to do so will result in expiration and loss of your hostname. Note that using an update client will no longer suffice for this monthly login. You will still continue to get email alerts every 30 days if your email address is current.
O dyn.com é um dos dois serviços de DNS dinâmico que eu usava até então para o meu computador de casa. O outro é o dnsdynamic.org, que no dia seguinte ao recebimento do e-mail, portanto em 16/05/2013, por coincidência ou não, parou de responder.
Pesquisando na Internet, encontrei os seguintes recursos:
- http://wiki.debian.org/DDNS
- http://linux.yyz.us/nsupdate/
- http://linux.yyz.us/dns/ddns-server.html
- http://web.archive.org/web/20120130200400/http://ops.ietf.org/dns/dynupd/secure-ddns-howto.html
Eu já administrava o meu próprio servidor DNS com endereços estáticos para o meu domínio arg.eti.br
,
usando o software BIND. Resolvi, então, configurá-lo para servir também como DNS dinâmico.
Configurei o cliente (meu computador de casa) e o servidor DNS para fazerem o seguinte:
-
O cliente precisa saber qual é o seu endereço IP atual atribuído pelo provedor de Internet. Para descobrir o seu endereço IP atual, o cliente pergunta para
vps1.arg.eti.br:9999
, onde roda um serviço que simplesmente retorna o endereço IP do cliente que conectar nele. Você pode usar esse serviço, se quiser. -
O cliente pergunta ao servidor DNS qual o endereço IP que o servidor DNS tem registrado para o cliente.
-
O cliente compara o seu endereço IP atual atribuído pelo provedor de Internet com o endereço IP informado pelo servidor DNS e, se forem diferentes, o cliente solicita ao servidor DNS que atualize o registro do endereço IP do cliente.
No cliente
No cliente, fiz o seguinte:
Gerei uma chave para ser usada pelo programa nsupdate
:
$ dnssec-keygen -A HMAC-MD5 -b 512 -HOST cliente.dynamic.arg.eti.br.
Criei um shell script chamado nsupdate.sh
:
#!/bin/sh
ZONE="dynamic.arg.eti.br"
HOST="cliente.$ZONE"
DNS_SERVER="ns1.arg.eti.br"
WIMI_SERVER="vps1.arg.eti.br" #WIMI=What Is My IP
WIMI_PORT=9999
SLEEP_OK=300
SLEEP_ERR=60
while true
do
IP_DNS=$(host -t A $HOST $DNS_SERVER | egrep -o "([0-9]{1,3}\.){3}[0-9]{1,3}$")
IP_WAN=$(nc $WIMI_SERVER $WIMI_PORT | egrep -o "^([0-9]{1,3}\.){3}[0-9]{1,3}$")
echo "$(date) IP_DNS=$IP_DNS, IP_WAN=$IP_WAN"
if [ -z "$IP_DNS" ]
then
echo "erro ao obter IP de $HOST via DNS"
sleep $SLEEP_ERR
continue
fi
if [ -z "$IP_WAN" ]
then
echo "erro ao obter IP da WAN"
sleep $SLEEP_ERR
continue
fi
if [ "$IP_DNS" != "$IP_WAN" ]
then
echo "atualizando novo IP $IP_WAN"
echo \
"server $DNS_SERVER.
zone $ZONE.
update delete $HOST. A
update add $HOST. 900 A $IP_WAN
show
send
" | nsupdate -k K$HOST.+157+49186.private
fi
sleep $SLEEP_OK
done
Rodei o script nsupdate.sh
(ainda preciso melhorar a chamada do script para executá-lo automaticamente ao inicializar o
computador):
$ nohup ./nsupdate.sh &
No servidor
No servidor, para configurar o BIND, fiz o seguinte:
Criei o arquivo /etc/bind/keys.conf
:
key cliente.dynamic.arg.eti.br. {
algorithm HMAC-MD5;
secret "<copie aqui a chave; ela segue o texto 'Key:' no arquivo .private gerado pelo dnssec-keygen>";
};
Incluí o arquivo /etc/bind/keys.conf
no arquivo /etc/bind/named.conf.local
, antes das declarações de
zonas:
include "/etc/bind/keys.conf";
Incluí no arquivo /etc/bind/named.conf.local
uma nova zona dynamic.arg.eti.br
:
zone "dynamic.arg.eti.br" {
type master;
file "/var/cache/bind/db.dynamic.arg.eti.br";
update-policy {
grant cliente.dynamic.arg.eti.br. name cliente.dynamic.arg.eti.br. A;
};
};
Criei um arquivo /var/cache/bind/db.dynamic.arg.eti.br
para a zona dynamic.arg.eti.br
:
;
; BIND data file for dynamic.arg.eti.br zone
;
$TTL 15m
@ IN SOA ns1.arg.eti.br. hostmaster.arg.eti.br. (
1 ; Serial
1d ; Refresh
15m ; Retry
1w ; Expire
15m ) ; Negative Cache TTL
;
@ IN NS ns1.arg.eti.br.
Testei a nova configuração:
sudo -u bind named-checkzone -D dynamic.arg.eti.br /var/cache/bind/db.dynamic.arg.eti.br
sudo -u bind named-checkconf -p -z
Apliquei a nova configuração:
sudo -u bind rndc reload
Atenção: caso seja necessário editar manualmente o arquivo /var/cache/bind/db.dynamic.arg.eti.br
após ter
sido aplicada a nova configuração, deve-se fazer assim:
sudo -u bind rndc freeze dynamic.arg.eti.br
sudo -u bind vi /var/cache/bind/db.dynamic.arg.eti.br
sudo -u bind named-checkzone -D dynamic.arg.eti.br /var/cache/bind/db.dynamic.arg.eti.br
sudo -u bind named-checkconf -p -z
sudo -u bind rndc thaw dynamic.arg.eti.br
Também no servidor, configurei o serviço que responde o endereço IP do cliente que conectar nele:
Criei o arquivo ~/src/whatismyip/whatismyip.py
:
#!/usr/bin/python
import SocketServer
import datetime
import time
class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
print str(datetime.datetime.now()), self.client_address[0]
self.request.sendall(self.client_address[0])
time.sleep(1)
if __name__ == "__main__":
HOST, PORT = "vps1.arg.eti.br", 9999
print "servidor iniciado em %s:%d" % (HOST, PORT)
server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
Rodei o script whatismyip.py
(ainda preciso melhorar a chamada do script para executá-lo automaticamente ao inicializar o
computador):
$ nohup ./whatismyip.py &
Bem, ainda não desativei os dois serviços de DNS dinâmico que eu usava, mas já estou usando o meu novo serviço "feito em casa" ;-)