Skip to content
 
 

Latest commit

 

History

285 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

zigdig

naive dns client library in zig

help me decide if this api is good: lun-4#10

what does it do

  • serialization and deserialization of dns packets as per rfc1035
  • supports a subset of rdata (i do not have any plans to support 100% of DNS, but SRV/MX/TXT/A/AAAA are there, which most likely will be enough for your use cases)
  • has helpers for reading /etc/resolv.conf (not that much, really)
  • classless IN-ADDR.ARPA (IPv4) and IP6.ARPA (IPv6) delegations (reverse lookups)

what does it not do

  • no edns0
  • support all resolv.conf options
  • can deserialize pointer labels, but does not serialize into pointers
  • follow CNAME records, this provides only the basic serialization/deserializtion

how do

  • zig 0.12.0: https://ziglang.org
  • have a /etc/resolv.conf
  • tested on linux, should work on bsd i think
git clone ...
cd zigdig

zig build test
zig build install --prefix ~/.local/

and then

zigdig google.com a

or, for the host(1) equivalent

zigdig-tiny google.com

using the library

getAddressList-style api

const dns = @import("dns");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer {
        _ = gpa.deinit();
    }
    var allocator = gpa.allocator();

    var addresses = try dns.helpers.getAddressList("ziglang.org", allocator);
    defer addresses.deinit();

    for (addresses.addrs) |address| {
        std.debug.print("we live in a society {}\n", .{address});
    }
}

full api

const dns = @import("dns");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer {
        _ = gpa.deinit();
    }
    var allocator = gpa.alloator();

    var name_buffer: [128][]const u8 = undefined;
    const name = try dns.Name.fromString("ziglang.org", &name_buffer);

    var questions = [_]dns.Question{
        .{
            .name = name,
            .typ = .A,
            .class = .IN,
        },
    };

    var packet = dns.Packet{
        .header = .{
            .id = dns.helpers.randomHeaderId(),
            .is_response = false,
            .wanted_recursion = true,
            .question_length = 1,
        },
        .questions = &questions,
        .answers = &[_]dns.Resource{},
        .nameservers = &[_]dns.Resource{},
        .additionals = &[_]dns.Resource{},
    };

    // use helper function to connect to a resolver in the systems'
    // resolv.conf

    const conn = try dns.helpers.connectToSystemResolver();
    defer conn.close();

    try conn.sendPacket(packet);

    // you can also do this to support any Writer
    // const written_bytes = try packet.writeTo(some_fun_writer_goes_here);

    const reply = try conn.receivePacket(allocator, 4096);
    defer reply.deinit();

    // you can also do this to support any Reader
    // const packet = try dns.Packet.readFrom(some_fun_reader, allocator);
    // defer packet.deinit();

    const reply_packet = reply.packet;
    logger.info("reply: {}", .{reply_packet});

    try std.testing.expectEqual(packet.header.id, reply_packet.header.id);
    try std.testing.expect(reply_packet.header.is_response);

    // ASSERTS that there's one A resource in the answer!!! you should verify
    // reply_packet.header.opcode to see if there's any errors

    const resource = reply_packet.answers[0];
    var resource_data = try dns.ResourceData.fromOpaque(
        reply_packet,
        resource.typ,
        resource.opaque_rdata,
        allocator
    );
    defer resource_data.deinit(allocator);

    // you now have an std.net.Address to use to your hearts content
    const ziglang_address = resource_data.A;
}

Reverse lookups examples

    // Ipv4
    const name = "dns.google.";
    const test_address = "8.8.4.4";
    var reverse = try dns.ReverseLookup.init(std.heap.page_allocator, test_address, 123);
    const names = try reverse.lookupIpv4();

    // Ipv6
    const test_address = "2001:4860:4860::8888";
    const name = "dns.google.";
    var reverse = try dns.ReverseLookup.init(std.heap.page_allocator, test_address, 123);
    const names = try reverse.lookupIpv6();

it is recommended to look at zigdig's source on src/main.zig to understand how things tick using the library, but it boils down to three things:

  • packet generation and serialization
  • sending/receiving (via a small shim on top of std.os.socket)
  • packet deserialization

About

naive dns client library in zig

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages