Introdução
DNS (Domain Name System) é o sistema que traduz nomes de domínio legíveis (como example.com) em endereços IP numéricos (como 93.184.216.34). A resolução DNS é fundamental para qualquer aplicação de rede.
Nesta receita, você aprenderá a fazer lookups DNS em Zig usando a biblioteca padrão, resolver nomes de domínio e trabalhar com diferentes tipos de endereços.
Pré-requisitos
- Zig instalado (versão 0.13+). Veja o guia de instalação
- Conhecimento básico de Zig. Consulte a introdução ao Zig
Resolução DNS Básica
Use std.net.Address.resolveIp para resolver nomes de domínio:
const std = @import("std");
const net = std.net;
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Resolver nome de domínio para endereço IP
const hostname = "example.com";
const port: u16 = 80;
const addrs = try net.getAddressList(allocator, hostname, port);
defer addrs.deinit();
std.debug.print("Endereços para '{s}':\n", .{hostname});
for (addrs.addrs) |addr| {
// Formatar o endereço como string
var buf: [64]u8 = undefined;
const addr_str = try std.fmt.bufPrint(&buf, "{}", .{addr});
std.debug.print(" {s}\n", .{addr_str});
}
}
Saída esperada
Endereços para 'example.com':
93.184.216.34:80
2606:2800:220:1:248:1893:25c8:1946:80
Resolver e Conectar
Combine resolução DNS com conexão TCP:
const std = @import("std");
const net = std.net;
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const hostname = "example.com";
const port: u16 = 80;
// Resolver e tentar conectar em cada endereço
const addrs = try net.getAddressList(allocator, hostname, port);
defer addrs.deinit();
var connected = false;
for (addrs.addrs) |addr| {
const stream = net.tcpConnectToAddress(addr) catch |err| {
std.debug.print("Falha ao conectar em {}: {}\n", .{ addr, err });
continue;
};
defer stream.close();
std.debug.print("Conectado a {s} em {}\n", .{ hostname, addr });
connected = true;
// Fazer algo com a conexão
const request =
"GET / HTTP/1.1\r\n" ++
"Host: example.com\r\n" ++
"Connection: close\r\n" ++
"\r\n";
_ = try stream.write(request);
var buffer: [1024]u8 = undefined;
const n = try stream.read(&buffer);
std.debug.print("Primeiros bytes da resposta:\n{s}\n", .{buffer[0..@min(n, 200)]});
break;
}
if (!connected) {
std.debug.print("Não foi possível conectar a {s}\n", .{hostname});
}
}
Resolver Múltiplos Domínios
Resolva vários domínios e compare seus endereços:
const std = @import("std");
const net = std.net;
fn resolveDomain(allocator: std.mem.Allocator, hostname: []const u8) void {
const addrs = net.getAddressList(allocator, hostname, 0) catch |err| {
std.debug.print("{s}: erro - {}\n", .{ hostname, err });
return;
};
defer addrs.deinit();
std.debug.print("{s}:\n", .{hostname});
if (addrs.addrs.len == 0) {
std.debug.print(" Nenhum endereço encontrado\n", .{});
return;
}
for (addrs.addrs) |addr| {
var buf: [64]u8 = undefined;
const addr_str = std.fmt.bufPrint(&buf, "{}", .{addr}) catch "???";
std.debug.print(" {s}\n", .{addr_str});
}
std.debug.print("\n", .{});
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const domains = [_][]const u8{
"google.com",
"github.com",
"ziglang.org",
"cloudflare.com",
};
for (&domains) |domain| {
resolveDomain(allocator, domain);
}
}
Verificar Disponibilidade de Host
Use resolução DNS para verificar se um host está acessível:
const std = @import("std");
const net = std.net;
const HostStatus = enum {
resolvido,
nao_encontrado,
erro_rede,
};
fn checkHost(allocator: std.mem.Allocator, hostname: []const u8) HostStatus {
const addrs = net.getAddressList(allocator, hostname, 0) catch {
return .nao_encontrado;
};
defer addrs.deinit();
if (addrs.addrs.len == 0) {
return .nao_encontrado;
}
// Tentar conectar na porta 80 para verificar acessibilidade
for (addrs.addrs) |addr| {
const check_addr = net.Address.initIp4(
if (addr.any.family == std.posix.AF.INET)
@as(*const [4]u8, @ptrCast(&addr.in.sa.addr)).*
else
continue,
80,
);
const stream = net.tcpConnectToAddress(check_addr) catch continue;
stream.close();
return .resolvido;
}
return .erro_rede;
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const hosts = [_][]const u8{
"google.com",
"dominio-inexistente-xyz.com",
"github.com",
};
for (&hosts) |host| {
const status = checkHost(allocator, host);
const status_str = switch (status) {
.resolvido => "OK - Acessível",
.nao_encontrado => "FALHA - Não encontrado",
.erro_rede => "AVISO - DNS ok, rede indisponível",
};
std.debug.print("{s}: {s}\n", .{ host, status_str });
}
}
Saída esperada
google.com: OK - Acessível
dominio-inexistente-xyz.com: FALHA - Não encontrado
github.com: OK - Acessível
Criar Endereço IP Diretamente
Quando você já sabe o IP, pode criar o endereço sem resolução DNS:
const std = @import("std");
const net = std.net;
pub fn main() !void {
// IPv4
const ipv4_addr = net.Address.initIp4(.{ 192, 168, 1, 1 }, 8080);
std.debug.print("IPv4: {}\n", .{ipv4_addr});
// IPv6
const ipv6_addr = net.Address.initIp6(
.{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, // ::1 (localhost)
8080,
0,
0,
);
std.debug.print("IPv6: {}\n", .{ipv6_addr});
// Parsear string de IP
const parsed = try net.Address.parseIp4("10.0.0.1", 443);
std.debug.print("Parseado: {}\n", .{parsed});
}
Dicas e Boas Práticas
Cache de DNS: Considere cachear resultados de DNS para evitar lookups repetidos em aplicações de alto desempenho.
Trate falhas: A resolução DNS pode falhar por diversos motivos. Sempre trate erros com o sistema de erros do Zig.
Múltiplos endereços: Um domínio pode resolver para vários IPs. Tente todos antes de falhar.
IPv4 e IPv6: Esteja preparado para lidar com ambos os protocolos.
Timeouts: DNS geralmente é rápido, mas pode ser lento em redes problemáticas.
Receitas Relacionadas
- Como criar um cliente TCP em Zig - Conectar após resolver DNS
- Como usar sockets UDP em Zig - DNS usa UDP internamente
- Como fazer requisições HTTP GET em Zig - HTTP resolve DNS automaticamente
- Como parsear URLs em Zig - Extrair hostname de URLs