Servidor DNS Unbound com Anablock

Apresento a vocês um tutorial simples de como criar um servidor DNS recursivo (usado para cache DNS de navegação local e navegação de usuários).

Leitura de outras dicas recomendadas:

  • Criação da maquina virtual VMware com ajustes finos;
  • Instalação do Debian 12 netinstall x86_64 (amd64);
  • Instalação de programas básicos;
  • Data/hora via NTP;
  • Ajuste fino no kernel Linux;

Instalando Unbound

Os procedimentos abaixo foram feitos e pensados para uma nova instalação limpa, não recomendo que você as execute em um servidor que já esteja rodando o Unbound.

Bash

# Instalar Unbound:
apt-get -y install unbound

# Instalar ferramentas de DNS:
apt-get -y install dnsutils

# Ativar no systemd para subir durante o boot:
systemctl enable unbound

# Baixar lista de root-servers atualizada:
mkdir -p /etc/unbound
wget https://www.internic.net/domain/named.root -4 -O /etc/unbound/named.cache

Precisamos obter a lista de root-servers atualizadas, os root-servers são servidores espalhados globalmente e possuem os dominos TLDN (.br, .com, .net, .io, .arpa., etc…) e possuem a zona raiz apontando para todos os servidores de segundo nível do mundo (.br aponta para registro.br no Brasil, .ar aponta para os servidores da Argentina, etc…).

Bash

# Baixar lista de root-servers atualizada:
mkdir -p /etc/unbound
wget https://www.internic.net/domain/named.root -4 -O /etc/unbound/named.cache

# Produzir listas em formato intercambiável para uso nos
# scripts diversos e de monitoramento
cat /etc/unbound/named.cache | egrep -v '^;'         > /tmp/nc-nocmts.txt
cat /tmp/nc-nocmts.txt       | egrep -v NS           > /tmp/nc-ipaddr.txt
cat /tmp/nc-ipaddr.txt       | awk '{print $1";"$4}' > /tmp/nc-table.dat
cat /tmp/nc-table.dat        | cut -f2 -d';'         > /tmp/nc-iponly.dat

# Arquivos finais:
cat /tmp/nc-table.dat   >  /etc/unbound/root-servers-table.dat
cat /tmp/nc-iponly.dat  >  /etc/unbound/root-servers-ips.dat
cat /tmp/nc-iponly.dat | egrep -v ':'  >  /etc/unbound/root-servers-ipv4.dat
cat /tmp/nc-iponly.dat | egrep    ':'  >  /etc/unbound/root-servers-ipv6.dat

Configurando Unbound do zero

Vamos limpar a configuração padrão e criar tudo do zero.

Bash

# Garantir config padrao no formato /etc/unbound/unbound.conf.d/
mkdir -p /etc/unbound/unbound.conf.d
rm    -f /etc/unbound/unbound.conf.d/* 2>/dev/null

# Recriar todas as configs do zero:
# - Config principal:
(
    echo
    echo 'server:'
    echo '    module-config: "respip validator iterator"'
    echo
    echo 'include-toplevel: "/etc/unbound/unbound.conf.d/*.conf"'
    echo
) > /etc/unbound/unbound.conf

Leia os comentários e altere de acordo com as suas necessidades, em seguida cole os blocos de código no terminal.

Bash

# - Chave pública da raiz do DNS (Root Zone Key), usado para DNSSEC:
(
    echo
    echo 'server:'
    echo
    echo '    auto-trust-anchor-file: "/var/lib/unbound/root.key"'
    echo
) > /etc/unbound/unbound.conf.d/21-root-auto-trust-anchor-file.conf

# - Gerador de estatísticas:
(
    echo 'server:'
    echo '    statistics-interval: 0'
    echo '    extended-statistics: yes'
    echo '    statistics-cumulative: no'
    echo
) > /etc/unbound/unbound.conf.d/31-statisticas.conf

# - Protocolos - ativar todos
# - Nota: coloque "no" no do-ip6 se você não tem IPv6 no servidor
(
    echo
    echo 'server:'
    echo
    echo '    do-ip4: yes'
    echo '    do-ip6: yes'
    echo '    do-udp: yes'
    echo '    do-tcp: yes'
    echo
) > /etc/unbound/unbound.conf.d/41-protocols.conf

# - ACL de uso - IPs locais (loopback e privados) confiaveis
# - Nota: IPs privados definidos em RFC para IPv4:
#         rfc  922, rfc  919, rfc 1112, rfc 1122,
#         rfc 1918, rfc 2544, rfc 3068, rfc 3171,
#         rfc 3330, rfc 3927, rfc 5735, rfc 5736,
#         rfc 5737, rfc 6598,
#
# - Nota: IPs privados/não-globais definidos em RFC para IPv6:
#         rfc 3849, rfc 9637
#
(
    echo
    echo 'server:'
    echo
    echo '    # Loopback'
    echo '    access-control: 127.0.0.1/32        allow'
    echo '    access-control: ::1/128             allow'
    echo
    echo '    # Todas as faixas privadas RFCs'
    echo '    access-control: 0.0.0.0/8           allow'
    echo '    access-control: 10.0.0.0/8          allow'
    echo '    access-control: 100.64.0.0/10       allow'
    echo '    access-control: 127.0.0.0/8         allow'
    echo '    access-control: 169.254.0.0/16      allow'
    echo '    access-control: 172.16.0.0/12       allow'
    echo '    access-control: 192.0.0.0/24        allow'
    echo '    access-control: 192.0.2.0/24        allow'
    echo '    access-control: 192.88.99.0/24      allow'
    echo '    access-control: 192.168.0.0/16      allow'
    echo '    access-control: 198.18.0.0/15       allow'
    echo '    access-control: 198.51.100.0/24     allow'
    echo '    access-control: 203.0.113.0/24      allow'
    echo '    access-control: 224.0.0.0/4         allow'
    echo '    access-control: 240.0.0.0/4         allow'
    echo '    access-control: 255.255.255.255/32  allow'

    echo '    # Faixas IPv6 privadas'
    echo '    access-control: 2001:db8::/32       allow'
    echo
    echo '    # Faixas IPv6 nao-globais'
    echo '    access-control: ::/3                allow'
    echo '    access-control: 4000::/2            allow'
    echo '    access-control: 8000::/1            allow'
    echo
) > /etc/unbound/unbound.conf.d/51-acls-locals.conf

# - ACL de uso - IPs locais públicos (IPv4) e globais (IPv6)
# - Nota: Coloque seus prefixos de IPs publicos,
#         prefixos de IPs delegados pelo seu provedor,
#         prefixos de IPs do seu ASN,
#         informe IPv4 e IPv6, mesmo se não usar o IPv6
#
(
    echo
    echo 'server:'
    echo
    echo '    # IPs publicos (IPv4) delegados e proprios:'
    echo '    access-control: 45.255.128.0/29     allow'
    echo
    echo '    # IPs globais (IPv6) delegados e proprios:'
    echo '    access-control: 2804:cafe::/126     allow'
    echo
) > /etc/unbound/unbound.conf.d/52-acls-trusteds.conf

# - ACL padrao - descartar tudo de IPs nao confiaveis
# - Nota: nao use "refuse" como padrão pois ele gera resposta
#         e pode fazer seu DNS ser explorado em DDoS
#         usar "deny" pois ele descarta silenciosamente
#         os pacotes de IPs desconhecidos
(
    echo
    echo 'server:'
    echo
    echo '    # Nao responder para IPs desconhecidos'
    echo '    access-control: 0.0.0.0/0 deny'
    echo '    access-control: ::/0      deny'
    echo
) > /etc/unbound/unbound.conf.d/59-acls-default-policy.conf

# Parametros gerais (tuning) - padrao para 4 nucleos, 64M de RAM
(
    echo
    echo 'server:'
    echo '    outgoing-range: 8192'
    echo '    outgoing-port-avoid: 0-1024'
    echo '    outgoing-port-permit: 1025-65535'
    echo '    num-threads: 4'
    echo '    num-queries-per-thread: 1024'
    echo '    msg-cache-size: 64m'
    echo '    msg-cache-slabs: 4'
    echo '    rrset-cache-size: 8m'
    echo '    rrset-cache-slabs: 4'
    echo '    cache-min-ttl: 60'
    echo '    cache-max-ttl: 7200'
    echo '    infra-host-ttl: 60'
    echo '    infra-lame-ttl: 120'
    echo '    infra-cache-numhosts: 10000'
    echo '    infra-cache-lame-size: 10k'
    echo '    infra-cache-slabs: 4'
    echo '    key-cache-slabs: 4'
    echo '    rrset-roundrobin: yes'
    echo
    echo '    hide-identity: yes'
    echo '    hide-version: yes'
    echo '    harden-glue: yes'
    echo '    harden-algo-downgrade: yes'
    echo '    harden-below-nxdomain: yes'
    echo '    harden-dnssec-stripped: yes'
    echo '    harden-large-queries: yes'
    echo '    harden-referral-path: no'
    echo '    harden-short-bufsize: yes'
    echo '    do-not-query-address: 127.0.0.1/8'
    echo '    do-not-query-localhost: yes'
    echo '    edns-buffer-size: 1472'
    echo '    aggressive-nsec: yes'
    echo '    delay-close: 10000'
    echo '    neg-cache-size: 4M'
    echo '    qname-minimisation: yes'
    echo '    deny-any: yes'
    echo '    ratelimit: 1000'
    echo '    unwanted-reply-threshold: 10000'
    echo '    use-caps-for-id: yes'
    echo '    val-clean-additional: yes'
    echo '    minimal-responses: yes'
    echo '    prefetch: yes'
    echo '    prefetch-key: yes'
    echo '    serve-expired: yes'
    echo '    so-reuseport: yes'
    echo
) > /etc/unbound/unbound.conf.d/61-configs.conf


# Informar em quais enderecos IP locais o unbound deve abrir
# a porta 53/tcp e 53/udp para escuta de requisicoes
# - Escutar sempre nos ips de loopback
(
    echo
    echo 'server:'
    echo '    interface: 127.0.0.1'
    echo '    interface: ::1'
    echo
) > /etc/unbound/unbound.conf.d/62-listen-loopback.conf

# - Escutar sempre nos ips externos
#   * usar 0.0.0.0 não é uma boa ideia, embora funcione
#     essa config causa assincronia no ip de resposta
#     nos casos em que o servidor tem mais de um IP
#   * correto: crie uma linha 'interface:' para cada IP
#     publico ou de loopback
(
    echo
    echo 'server:'
    echo '    interface: 0.0.0.0'
    echo '    interface: ::'
    echo
) > /etc/unbound/unbound.conf.d/63-listen-interfaces.conf


# - Hyperlocal Cache (opcional)
# -- Requer lista de root-servers do inicio do tutorial!
if [ -f /etc/unbound/root-servers-ips.dat ]; then
    (
        echo
        echo 'server:'
        echo '    auth-zone:'
        echo '        name: "."'
        for addr in $(cat /etc/unbound/root-servers-ips.dat); do
            echo "            master: $addr"
        done
        echo '        fallback-enabled: yes'
        echo '        for-downstream: no'
        echo '        for-upstream: yes'
        echo '        zonefile: ""'
        echo
    ) > /etc/unbound/unbound.conf.d/89-hyperlocal-cache.conf
fi

# - Controle remoto local do processo:
# - Nota: somente localhost, por isso nao precisa de certificado
(
    echo
    echo 'remote-control:'
    echo '    control-enable: yes'
    echo '    control-interface: 127.0.0.1'
    echo '    control-port: 953'
    echo '    control-use-cert: "no"'
    echo '    control-interface: /run/unbound.ctl'
    echo
) > /etc/unbound/unbound.conf.d/99-remote-control.conf

Testando e executando

Até aqui temos a configuração de um servidor Unbound para DNS Recursivo de alta qualidade. Vamos testar antes de continuar para a fase 2.

Bash

# Conferir se a configuração está OK:
unbound-checkconf  /etc/unbound/unbound.conf
    # precisa retornar:
    # unbound-checkconf: no errors in /etc/unbound/unbound.conf

# Rodar e testar:
service  unbound   stop
service  unbound   start

# Verificar status de execução:
service  unbound   status

Homologação de DNS

Com o Unbound rodando, vamos testar se ele resolve nomes:

Bash

# Testar DNS enviando requisição para o ip de Loopback
# usando varias ferramentas de DNS:
nslookup   www.google.com   127.0.0.1
host       www.google.com   127.0.0.1
dig  @127.0.0.1   www.google.com

# Caso tenha ativado o IPv6 em "do-ip6", teste tambem:
nslookup   www.google.com   ::1
host       www.google.com   ::1
dig  @::1  www.google.com

# Nota: ping não é ferramenta de teste de DNS!

Caso você enfrente problemas ao resolver nomes, confira se os pacotes estão sendos respondidos, se seu servidor tem acesso a DNS na Internet, testes pontuais (ping e traceroute não são ferramentas de teste de DNS).

Testando acesso externo de DNS para homologação

Bash

# 1 - Testar usando servidores de DNS recursivo abertos
# 1.1 - Usando UDP:
dig  @1.0.0.1       www.google.com
dig  @1.1.1.1       www.google.com
dig  @4.2.2.2       www.google.com
dig  @4.2.2.6       www.google.com
dig  @8.8.4.4       www.google.com
dig  @8.8.8.8       www.google.com
dig  @9.9.9.9       www.google.com

# 1.2 - Usando TCP:
dig  @1.0.0.1 +tcp  www.google.com
dig  @1.1.1.1 +tcp  www.google.com
dig  @4.2.2.2 +tcp  www.google.com
dig  @4.2.2.6 +tcp  www.google.com
dig  @8.8.4.4 +tcp  www.google.com
dig  @8.8.8.8 +tcp  www.google.com
dig  @9.9.9.9 +tcp  www.google.com

# 2 - Testar acesso ao root-server a.root-server.net
dig @198.41.0.4      -t ns root-server.net
dig @198.41.0.4 +tcp -t ns root-server.net

Se você encontrar algum problema nos testes acima, investigue e arrume-o antes de continuar.

Implementando AnaBlock

O AnaBlock é uma API de automação de bloqueios judiciais, essa API é hospedada no site anablock.net.br e requer cadastro para ter o acesso, acesse o site https://anablock.net.br/ para se cadastrar.

Nota: somente provedores cadastrados na Anatel (com dispensa ou outorga) devidamente notificados pela Anatel para realizar bloqueios podem ter acesso a API pois os dados retornados possuem segredo de justiça.

Após cadastrar e liberar seus IPs (IPv4 e/ou IPv6) na API do AnaBlock, teste se a API está operacional:

Bash

# Testar se a liberação foi realizada:
    # Teste de liberacao via IPv4:
    curl -4 https://anablock.net.br/acl.php

    # Teste de liberacao via IPv6:
    curl -6 https://anablock.net.br/acl.php

    # Forcar testar apenas IPv4:
    curl http://v4.anablock.net.br/acl.php

    # Forcar testar apenas IPv6:
    curl http://v6.anablock.net.br/acl.php

# Testar se a lista de domínios está sendo enviada
    mkdir /etc/anablock
    ABLIST="/etc/anablock/anablock.domains"
    ABURL="https://api.anablock.net.br/api/domain/all"
    curl -v -o $ABLIST $ABURL

# Verificar a contagem de domínios na lista
   cat /etc/anablock/anablock.domains | wc -l

Se tudo deu certo até aqui, chegou a hora de colocar o Unbound para bloquear automaticamente os domínios ordenados pela justiça/Anatel.

Crie a configuração do AnaBlock no Unbound:

Bash

# Criar arquivo de cache RPZ
mkdir -p /var/lib/unbound
touch    /var/lib/unbound/anablock-rpz.zone
chown unbound:unbound /var/lib/unbound/anablock-rpz.zone

# Criar entrada na config do Unbound:
(
    echo
    echo 'server:'
    echo '    rpz:'
    echo '        name: "anablock"'
    echo '        zonefile: "/var/lib/unbound/anablock-rpz.zone"'
    echo
    echo 'auth-zone:'
    echo '    name: "anablock"'
    echo '    url: "https://api.anablock.net.br/domains/rpz"'
    echo '    for-downstream: no'
    echo '    for-upstream: yes'
    echo '    fallback-enabled: no'
    echo '    zonefile: "/var/lib/unbound/anablock-rpz.zone"'
    echo
) > /etc/unbound/unbound.conf.d/91-anablock.conf

Testar se a nova configuração entrou harmonicamente no Unbound:

Bash

# Conferir se a configuração está OK:
unbound-checkconf  /etc/unbound/unbound.conf
    # precisa retornar:
    # unbound-checkconf: no errors in /etc/unbound/unbound.conf

# Reiniciar, escolha uma das ocoes:
    # 1 - Reiniciar sem perder o cache de DNS:
    unbound-control reload_keep_cache

    # 2 - Reiniciar unbound completamente e rapido:
    service unbound restart

    # 3 - Parar totalmente, esperar e iniciar do zero:
    service  unbound   stop
    service  unbound   start

# Verificar status de execução:
service  unbound   status

Testar bloqueios do AnaBlock

A API do AnaBlock fornece um nome de teste: blocktest.anablock.net.br

Se este nome for resolvido, o AnaBlock não está em operação, mas se apresentar erro NXDOMAIN (domínio não existe), o bloqueio foi implementado com sucesso.

Bash

# Teste de bloqueio:
host blocktest.anablock.net.br  127.0.0.1
    Using domain server:
    Name: 127.0.0.1
    Address: 127.0.0.1#53
    Aliases: 

    Host blocktest.anablock.net.br not found: 3(NXDOMAIN)

Com isso temos nosso bloqueio judicial 100% em conformidade com o jurídico da empresa via AnaBlock e um DNS de altíssima velocidade com Unbound.

Um abraço a todos,
Patrick Brandão, patrickbrandao@gmail.com