Skip to content

DoH: como funciona a consulta DNS no Clear Address?

Published at

🇧🇷 TabNews on 2024-07-06
🇧🇷 Dev.to on 2024-08-08

Olá!

Recentemente, o valterpatrick sugeriu que a gente mostrasse como as consultas DNS são realizadas no site clear-address.rda.run. Nós agradecemos demais a pergunta, até porque ela nos permite conversar sobre um assunto que consideramos fascinante: o DNS over HTTPS (DoH). Afinal, quem não gosta de entender o que acontece por trás de um clique?

Em vez de nós usarmos o protocolo DNS tradicional, que geralmente opera sem criptografia na porta 53, a gente aproveita as APIs públicas de resolvedores que suportam HTTPS. Na prática, isso transforma uma consulta DNS em uma chamada HTTP comum. Você já parou para pensar no ganho de privacidade que isso traz? Como a consulta se camufla no meio do tráfego HTTPS padrão, nós garantimos uma camada extra de segurança para os dados.

A Mágica por Trás da Cortina: As APIs

No backend do Clear Address, a gente faz chamadas para resolvedores DoH de peso, como os da Cloudflare e do Google. Embora a escolha entre eles possa variar conforme a necessidade, o princípio que nós seguimos é rigorosamente o mesmo.

A ideia central é simples: enviamos uma requisição GET para um endpoint específico, passando o domínio e o tipo de registro que a gente quer como parâmetros na URL. O servidor, então, nos devolve um JSON com tudo o que precisamos. Simples, não é?

DoH via Cloudflare

A Cloudflare é uma das referências quando falamos desses serviços. Nós consultamos a documentação deles, que está disponível aqui, para montar nossa integração.

Se a gente quiser consultar o registro AAAA (o endereço IPv6) do próprio clear-address.rda.run, a URL da API que nós usamos fica assim:

js
https://cloudflare-dns.com/dns-query?name=clear-address.rda.run&type=AAAA

Usando cURL

Dá para testar isso agora mesmo no terminal usando o cURL. Nós só precisamos lembrar de passar o header Accept para que a Cloudflare envie a resposta em JSON. Será que funciona de primeira?

bash
curl -H 'Accept: application/dns-json' 'https://cloudflare-dns.com/dns-query?name=clear-address.rda.run&type=AAAA'

Usando Go

No nosso backend, o processo segue essa mesma lógica. Abaixo, a gente mostra um exemplo básico em Go de como realizar essa chamada e tratar os dados recebidos.

go
package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

// Estrutura para receber a resposta da API da Cloudflare
type DNSResponse struct {
    Status   int  `json:"Status"`
    TC       bool `json:"TC"`
    RD       bool `json:"RD"`
    RA       bool `json:"RA"`
    AD       bool `json:"AD"`
    CD       bool `json:"CD"`
    Question []struct {
        Name string `json:"name"`
        Type int    `json:"type"`
    } `json:"Question"`
    Answer []struct {
        Name string `json:"name"`
        Type int    `json:"type"`
        TTL  int    `json:"TTL"`
        Data string `json:"data"`
    } `json:"Answer"`
}

func main() {
    // URL da API da Cloudflare para a consulta desejada
    url := "https://cloudflare-dns.com/dns-query?name=clear-address.rda.run&type=AAAA"

    // Cria uma nova requisição
    req, err := http.NewRequest("GET", url, nil)
    if err != nil {
        panic(err)
    }

    // Adiciona o header 'Accept' para especificar o formato da resposta
    req.Header.Add("Accept", "application/dns-json")

    // Executa a requisição
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    // Lê o corpo da resposta
    body, err := io.ReadAll(resp.Body)
    if err != nil {
        panic(err)
    }

    // Decodifica o JSON na nossa struct
    var dnsResp DNSResponse
    if err := json.Unmarshal(body, &dnsResp); err != nil {
        panic(err)
    }

    // Imprime os resultados
    fmt.Println("Resultados da consulta DNS:")
    if len(dnsResp.Answer) > 0 {
        for _, answer := range dnsResp.Answer {
            fmt.Printf(" - Domínio: %s\n", answer.Name)
            fmt.Printf("   Tipo: AAAA\n")
            fmt.Printf("   TTL: %d\n", answer.TTL)
            fmt.Printf("   Endereço IPv6: %s\n", answer.Data)
        }
    } else {
        fmt.Println("Nenhum registro AAAA encontrado.")
    }
}

DoH via Google

O Google também oferece um serviço muito parecido, que nós podemos conferir aqui. A lógica é idêntica; a gente só precisa ajustar a URL.

text
https://dns.google/resolve?name=clear-address.rda.run&type=AAAA

A implementação que nós faríamos, seja com cURL ou Go, seguiria o padrão anterior. Basta a gente adaptar a estrutura do JSON de resposta, que costuma ter sutis diferenças entre os provedores.

Backend vs. Frontend

Nós precisamos destacar um ponto importante: no Clear Address, essas chamadas ficam sempre do lado do backend. A gente nunca tentou fazer isso diretamente pelo frontend com JavaScript no navegador. Você já teve problemas com CORS ao tentar algo parecido? Para nós, centralizar essa lógica no servidor simplifica a vida e mantém a integridade do negócio.

Conclusão

Viram como não tem mistério? Nós apenas conectamos o Clear Address às APIs públicas de grandes empresas para resolver nomes de domínio com total segurança. A gente acredita que a transparência sobre como as ferramentas funcionam é fundamental para todo desenvolvedor.