srctree

Gregory Mullen parent 80d913fd 23d8b074
send/recv a working datagram

src/dns.zig added: 106, removed: 26, total 80
@@ -37,6 +37,30 @@ pub const Message = struct {
class: Class,
 
pub const Name = []Label;
 
pub fn init(a: Allocator, name: []const u8) !Question {
const label = try a.alloc(Label, std.mem.count(u8, name, "."));
var itr = std.mem.splitScalar(u8, name, '.');
for (label) |*l| {
const n = itr.next().?;
l.* = .{
.len = @intCast(n.len),
.name = n,
};
}
return .{
.name = label,
.qtype = .a,
.class = .in,
};
}
 
pub fn write(q: Question, w: *std.io.AnyWriter) !void {
for (q.name) |l| try l.write(w);
try w.writeByte(0);
try w.writeInt(u16, @intFromEnum(q.qtype), .big);
try w.writeInt(u16, @intFromEnum(q.class), .big);
}
};
 
pub const Resource = struct {
@@ -46,6 +70,8 @@ pub const Message = struct {
ttl: u32,
rdlength: u16,
data: void,
 
pub fn write(_: Resource) void {}
};
 
pub const Type = enum(u16) {
@@ -82,33 +108,24 @@ pub const Message = struct {
_,
};
 
pub const Authority = struct {};
pub const Authority = struct {
pub fn write(_: Authority) void {}
};
 
pub const Additional = struct {};
pub const Additional = struct {
pub fn write(_: Additional) void {}
};
 
pub fn query(a: Allocator, fqdn: []const []const u8) !Message {
const queries = try a.alloc(Question, fqdn.len);
for (queries, fqdn) |*q, dn| {
const label = try a.alloc(Label, std.mem.count(u8, dn, "."));
var itr = std.mem.splitScalar(u8, dn, '.');
for (label) |*l| {
const n = itr.next().?;
l.* = .{
.len = @intCast(n.len),
.name = n,
};
}
q.* = .{
.name = label,
.qtype = .a,
.class = .in,
};
q.* = try .init(a, dn);
}
 
// TODO only byteswap when endian changes
return .{
.header = .{
.id = @byteSwap(@as(u16, 31337)),
.id = @as(u16, 31337),
.qr = false,
.opcode = 0,
.aa = false,
@@ -116,7 +133,7 @@ pub const Message = struct {
.rd = true,
.ra = false,
.rcode = .success,
.qdcount = @byteSwap(@as(u16, @truncate(queries.len))),
.qdcount = @as(u16, @truncate(queries.len)),
.ancount = 0,
.nscount = 0,
.arcount = 0,
@@ -125,10 +142,34 @@ pub const Message = struct {
};
}
 
pub fn write(m: Message, buffer: []u8) !usize {
var fbs = std.io.fixedBufferStream(buffer);
var writer = fbs.writer();
var w = writer.any();
try w.writeInt(u96, @bitCast(m.header), .big);
if (m.question) |quest| for (quest) |q| {
try q.write(&w);
};
 
if (m.answer) |answer| for (answer) |a| {
a.write();
};
 
if (m.authority) |authort| for (authort) |a| {
a.write();
};
 
if (m.additional) |addit| for (addit) |a| {
a.write();
};
 
return fbs.pos;
}
 
test query {
const q = try query(std.testing.allocator, &[1][]const u8{"gr.ht."});
try std.testing.expectEqual(
@as(u96, 32643419703672757439099305984),
@as(u96, 37884113131630398792389361664),
@as(u96, @bitCast(q.header)),
);
for (q.question.?) |qst| {
@@ -141,6 +182,11 @@ pub const Message = struct {
pub const Label = struct {
len: u6,
name: []const u8,
 
pub fn write(l: Label, w: *std.io.AnyWriter) !void {
try w.writeByte(l.len);
try w.writeAll(l.name);
}
};
 
test "Message.Header" {
@@ -166,15 +212,49 @@ test "Message.Header" {
}
 
pub fn main() !void {
std.debug.print("All your {s} are belong to us.\n", .{"codebase"});
const a = std.heap.page_allocator;
std.debug.print("started\n", .{});
 
const stdout_file = std.io.getStdOut().writer();
var bw = std.io.bufferedWriter(stdout_file);
const stdout = bw.writer();
const addr: std.net.Address = .{ .in = .{ .sa = .{
.port = std.mem.nativeToBig(u16, 53),
.addr = std.mem.bytesToValue(u32, &[4]u8{ 0, 0, 0, 0 }),
} } };
 
try stdout.print("Run `zig build test` to run the tests.\n", .{});
const msg = try Message.query(a, &[1][]const u8{"gr.ht."});
var request: [1024]u8 = undefined;
const msgsize = try msg.write(&request);
 
try bw.flush();
std.debug.print("msg {}\n", .{msgsize});
std.debug.print("data {any}\n", .{request[0..msgsize]});
std.debug.print("data {s}\n", .{request[0..msgsize]});
 
const sock = try std.posix.socket(std.posix.AF.INET, std.posix.SOCK.DGRAM, 0);
try std.posix.connect(sock, &addr.any, addr.getOsSockLen());
const ocnt = try std.posix.send(sock, request[0..msgsize], 0);
std.debug.print("sent {}\n", .{ocnt});
 
var buffer: [1024]u8 = undefined;
const icnt = try std.posix.recv(sock, &buffer, 0);
std.debug.print("received {}\n", .{icnt});
std.debug.print("data {any}\n", .{buffer[0..icnt]});
std.debug.print("data {s}\n", .{buffer[0..icnt]});
 
std.debug.print("done\n", .{});
}
 
pub fn server() !void {
const sock = try std.posix.socket(std.posix.AF.INET, std.posix.SOCK.DGRAM, std.posix.SOCK.NONBLOCK);
 
const addr: std.net.Address = .{ .in = .{ .sa = .{
.port = 53,
.addr = 0,
} } };
const bind = try std.posix.bind(sock, &addr.any, addr.getOsSockLen());
_ = bind;
 
const buffer: [1024]u8 = undefined;
const icnt = try std.posix.recv(sock, &buffer, 0);
std.debug.print("sent {}\n", .{icnt});
}
 
test "simple test" {}