Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Limited implementation (no options) of EDNS #7

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ pub fn build(b: *std.Build) void {
.target = target,
.optimize = optimize,
});
const zig_network = b.createModule(.{ .source_file = .{ .path = "zig-network/network.zig" }});
exe.addModule("network", zig_network);
const zig_network = b.createModule(.{ .root_source_file = .{ .path = "zig-network/network.zig" }});
exe.root_module.addImport("network", zig_network);
b.installArtifact(exe);

const iter = b.addExecutable(.{
Expand All @@ -20,7 +20,7 @@ pub fn build(b: *std.Build) void {
.target = target,
.optimize = optimize,
});
iter.addModule("network", zig_network);
iter.root_module.addImport("network", zig_network);
b.installArtifact(iter);

const run_cmd = b.addRunArtifact(exe);
Expand Down
66 changes: 63 additions & 3 deletions src/dns.zig
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,59 @@ pub fn createQuery(allocator: mem.Allocator, address: []const u8, qtype: QType)
return message;
}

pub const EDNS = struct {
bufsize: u16 = 1232,
do_dnssec: bool = true,
// In the future, EDNS options will come here

pub fn format(self: *const EDNS, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) @TypeOf(writer).Error!void {
_ = fmt; // We don't use these two parameters
_ = options;
try writer.print(" EDNS {{\n", .{});
try writer.print(" Payload size: {d}\n", .{self.bufsize});
try writer.print(" Do DNSSEC: {any}\n", .{self.do_dnssec});
try writer.print(" }}\n", .{});
}
};

pub const PackedEDNSTTL = packed struct(u32) {
z2: u8 = 0,
z1: u7 = 0, // Zig put fields in the unexpected order inside a byte.
do: bool = true,
version: u8 = 0, // EDNS version 0 (RFC 6891)
extendedRcode: u8 = 0,
};

pub fn createEDNSQuery(allocator: mem.Allocator, address: []const u8, qtype: QType, edns: EDNS) !Message {
var result = try createQuery(allocator, address, qtype);
result.header.additional_record_count += 1;
const domain = try DomainName.from_string(allocator, ".");
var flags = PackedEDNSTTL{};
flags.do = edns.do_dnssec;
const rr: ResourceRecord = .{
.name = domain,
.type = Type.OPT,
.class = @enumFromInt(edns.bufsize),
.ttl = @as(i32, @bitCast(flags)),
.resource_data_length = 0, // We do not yet handle EDNS options ({attribute,value} pairs)
.resource_data = ResourceData{ .null = undefined },
};
var rrset = ResourceRecordList.init(allocator);
defer listDeinit(rrset);
try rrset.append(rr);
result.additional = try rrset.toOwnedSlice();
return result;
}

/// DNS Message. All communications inside of the domain protocol are
/// carried in a single format called a message.
pub const Message = struct {
allocator: mem.Allocator,
/// Contains information about the message. The header section is
/// always present
header: Header,
// EDNS information
edns: ?EDNS = null,
/// The question(s) being asked in the query. This section usually
/// contains one question.
questions: []const Question,
Expand Down Expand Up @@ -120,14 +166,21 @@ pub const Message = struct {
errdefer listDeinit(additional);

var add_idx: usize = 0;
var edns: ?EDNS = null;
while (add_idx < header.additional_record_count) : (add_idx += 1) {
const addit = try ResourceRecord.from_reader(allocator, reader);
try additional.append(addit);
if (addit.type == Type.OPT) {
const flags: PackedEDNSTTL = @as(PackedEDNSTTL, @bitCast(addit.ttl));
const do: bool = flags.do;
edns = .{ .bufsize = @intFromEnum(addit.class), .do_dnssec = do };
} else {
try additional.append(addit);
}
}

return Message{
.allocator = allocator,
.header = header,
.edns = edns,
.questions = try questions.toOwnedSlice(),
.answers = try answers.toOwnedSlice(),
.authorities = try authorities.toOwnedSlice(),
Expand Down Expand Up @@ -176,6 +229,9 @@ pub const Message = struct {
_ = options;
try writer.print("Message {{\n", .{});
try writer.print("{any}", .{self.header});
if (self.edns != null) {
try writer.print("{any}", .{self.edns});
}
try writer.print(" Questions {{\n", .{});
for (self.questions) |question| {
try writer.print("{any}", .{question});
Expand Down Expand Up @@ -238,6 +294,7 @@ pub const Message = struct {
const message = Message{
.allocator = self.allocator,
.header = self.header,
.edns = self.edns,
.questions = try questions.toOwnedSlice(),
.answers = try answers.toOwnedSlice(),
.authorities = try authorities.toOwnedSlice(),
Expand Down Expand Up @@ -532,7 +589,7 @@ pub const ResourceRecord = struct {
}
};

/// DNS Resource Record types
/// DNS Resource Record types https://www.iana.org/assignments/dns-parameters/dns-parameters.xml#dns-parameters-4
pub const Type = enum(u16) {
/// A host address
A = 1,
Expand Down Expand Up @@ -574,6 +631,8 @@ pub const Type = enum(u16) {
LOC = 29,
/// Service locator
SRV = 33,
// EDNS record
OPT = 41,
/// SSH Fingerprint
SSHFP = 44,
/// Uniform Resource Identifier
Expand Down Expand Up @@ -618,6 +677,7 @@ pub const Class = enum(u16) {
CH = 3,
/// Hesiod [Dyer 87]
HS = 4,
_, // Non-exhaustive enums for EDNS, where "class" is the payload size

pub fn format(self: Class, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) @TypeOf(writer).Error!void {
_ = fmt;
Expand Down