Compare commits
No commits in common. "7cf3bccc7640970f445b29f1b512282e6ec3d1d7" and "6e89c63eca455338190e6bc9bf44c0317e745a46" have entirely different histories.
7cf3bccc76
...
6e89c63eca
2 changed files with 53 additions and 30 deletions
60
src/mdns.zig
60
src/mdns.zig
|
@ -12,17 +12,19 @@ const MDNSError = error{
|
||||||
SocketSetTimeoutFail,
|
SocketSetTimeoutFail,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn get_mdns(domain: util.Domain, ip_info: util.IP_VER) !util.IP {
|
pub fn get_mdns(domain: util.Domain, ip_info: util.IPInfo) !util.IP {
|
||||||
if (ip_info != .Both) {
|
if (ip_info.version != .Both) {
|
||||||
const sock = try send_query(domain, ip_info);
|
const sock = try send_query(domain, ip_info);
|
||||||
return receive_response(sock, ip_info);
|
return receive_response(sock, ip_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
var sock = try send_query(domain, .IPv4);
|
const ip_info4 = util.IPInfo{ .version = .IPv4, .interface = ip_info.interface };
|
||||||
const addr_v4 = try receive_response(sock, .IPv4);
|
var sock = try send_query(domain, ip_info4);
|
||||||
|
const addr_v4 = try receive_response(sock, ip_info4);
|
||||||
|
|
||||||
sock = try send_query(domain, .IPv4);
|
const ip_info6 = util.IPInfo{ .version = .IPv6, .interface = ip_info.interface };
|
||||||
const addr_v6 = try receive_response(sock, .IPv6);
|
sock = try send_query(domain, ip_info6);
|
||||||
|
const addr_v6 = try receive_response(sock, ip_info6);
|
||||||
|
|
||||||
return util.merge_addrs(addr_v4, addr_v6);
|
return util.merge_addrs(addr_v4, addr_v6);
|
||||||
}
|
}
|
||||||
|
@ -30,10 +32,10 @@ pub fn get_mdns(domain: util.Domain, ip_info: util.IP_VER) !util.IP {
|
||||||
const socket = c_int;
|
const socket = c_int;
|
||||||
const MSG_BUFF_SIZE = util.consts.MSG_BUFF_SIZE;
|
const MSG_BUFF_SIZE = util.consts.MSG_BUFF_SIZE;
|
||||||
|
|
||||||
fn get_mdns_socket(ip_info: util.IP_VER) !socket {
|
fn get_mdns_socket(ip_info: util.IPInfo) !socket {
|
||||||
const sock = std.c.socket(switch (ip_info) {
|
const sock = std.c.socket(switch (ip_info.version) {
|
||||||
.IPv4 => std.c.AF.INET,
|
util.IP_VER_ENUM.IPv4 => std.c.AF.INET,
|
||||||
.IPv6 => std.c.AF.INET6,
|
util.IP_VER_ENUM.IPv6 => std.c.AF.INET6,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}, std.c.SOCK.DGRAM, std.c.IPPROTO.UDP);
|
}, std.c.SOCK.DGRAM, std.c.IPPROTO.UDP);
|
||||||
if (sock == -1) {
|
if (sock == -1) {
|
||||||
|
@ -46,7 +48,7 @@ fn get_mdns_socket(ip_info: util.IP_VER) !socket {
|
||||||
return sock;
|
return sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn construct_mdns_query(domain: util.Domain, ip_info: util.IP_VER, buff: []u8) !usize {
|
fn construct_mdns_query(domain: util.Domain, ip_info: util.IPInfo, buff: []u8) !usize {
|
||||||
var n: usize = 0;
|
var n: usize = 0;
|
||||||
var buff_writer = std.io.fixedBufferStream(buff);
|
var buff_writer = std.io.fixedBufferStream(buff);
|
||||||
|
|
||||||
|
@ -66,9 +68,9 @@ fn construct_mdns_query(domain: util.Domain, ip_info: util.IP_VER, buff: []u8) !
|
||||||
n += try buff_writer.write(&[_]u8{0x00}); // End null byte
|
n += try buff_writer.write(&[_]u8{0x00}); // End null byte
|
||||||
|
|
||||||
const question_footer =
|
const question_footer =
|
||||||
[_]u8{ 0x00, switch (ip_info) {
|
[_]u8{ 0x00, switch (ip_info.version) {
|
||||||
.IPv4 => 0x01,
|
util.IP_VER_ENUM.IPv4 => 0x01,
|
||||||
.IPv6 => 0x1c,
|
util.IP_VER_ENUM.IPv6 => 0x1c,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
} } ++ // A or AAAA record
|
} } ++ // A or AAAA record
|
||||||
[_]u8{ 0x00, 0x01 } // IN query
|
[_]u8{ 0x00, 0x01 } // IN query
|
||||||
|
@ -78,16 +80,22 @@ fn construct_mdns_query(domain: util.Domain, ip_info: util.IP_VER, buff: []u8) !
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_target_address(ip_info: util.IP_VER) !std.net.Address {
|
fn get_target_address(ip_info: util.IPInfo) !std.net.Address {
|
||||||
const target_addr: []const u8 = switch (ip_info) {
|
const target_addr: []const u8 = switch (ip_info.version) {
|
||||||
.IPv4 => "224.0.0.251",
|
util.IP_VER_ENUM.IPv4 => "224.0.0.251",
|
||||||
.IPv6 => "ff02::fb",
|
util.IP_VER_ENUM.IPv6 => blk: {
|
||||||
|
var buf: [50]u8 = undefined;
|
||||||
|
var byte_buf = std.io.fixedBufferStream(&buf);
|
||||||
|
const writer = byte_buf.writer();
|
||||||
|
try std.fmt.format(writer, "ff02::fb%{s}", .{ip_info.interface.?});
|
||||||
|
break :blk buf[0..writer.context.pos];
|
||||||
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
return std.net.Address.resolveIp(target_addr, 5353);
|
return std.net.Address.resolveIp(target_addr, 5353);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_query(domain: util.Domain, ip_info: util.IP_VER) !socket {
|
fn send_query(domain: util.Domain, ip_info: util.IPInfo) !socket {
|
||||||
const sock = try get_mdns_socket(ip_info);
|
const sock = try get_mdns_socket(ip_info);
|
||||||
errdefer _ = std.c.close(sock);
|
errdefer _ = std.c.close(sock);
|
||||||
|
|
||||||
|
@ -102,7 +110,7 @@ fn send_query(domain: util.Domain, ip_info: util.IP_VER) !socket {
|
||||||
return sock;
|
return sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_response(sock: socket, ip_info: util.IP_VER) !util.IP {
|
fn receive_response(sock: socket, ip_info: util.IPInfo) !util.IP {
|
||||||
defer _ = std.c.close(sock);
|
defer _ = std.c.close(sock);
|
||||||
|
|
||||||
var buff: [MSG_BUFF_SIZE]u8 = undefined;
|
var buff: [MSG_BUFF_SIZE]u8 = undefined;
|
||||||
|
@ -133,7 +141,7 @@ inline fn read_u16(bytes: []u8) u16 {
|
||||||
return std.mem.nativeToBig(u16, std.mem.bytesToValue(u16, bytes));
|
return std.mem.nativeToBig(u16, std.mem.bytesToValue(u16, bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_mdns_response(response: []u8, ip_info: util.IP_VER) !util.IP {
|
fn parse_mdns_response(response: []u8, ip_info: util.IPInfo) !util.IP {
|
||||||
var pos: usize = 0;
|
var pos: usize = 0;
|
||||||
|
|
||||||
if (response[2] & 0x80 == 0) { // check packet is response
|
if (response[2] & 0x80 == 0) { // check packet is response
|
||||||
|
@ -156,9 +164,9 @@ fn parse_mdns_response(response: []u8, ip_info: util.IP_VER) !util.IP {
|
||||||
const ip_bytes = response[pos .. pos + ip_len];
|
const ip_bytes = response[pos .. pos + ip_len];
|
||||||
pos += ip_len;
|
pos += ip_len;
|
||||||
|
|
||||||
if (switch (ip_info) {
|
if (switch (ip_info.version) {
|
||||||
.IPv4 => ip_len != 4,
|
util.IP_VER_ENUM.IPv4 => ip_len != 4,
|
||||||
.IPv6 => ip_len != 16,
|
util.IP_VER_ENUM.IPv6 => ip_len != 16,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}) {
|
}) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -173,14 +181,14 @@ fn parse_mdns_response(response: []u8, ip_info: util.IP_VER) !util.IP {
|
||||||
if (ip_bytes[0] == 0xfd) {
|
if (ip_bytes[0] == 0xfd) {
|
||||||
var addr_buff: [16]u8 = undefined;
|
var addr_buff: [16]u8 = undefined;
|
||||||
@memcpy(&addr_buff, ip_bytes);
|
@memcpy(&addr_buff, ip_bytes);
|
||||||
addr = std.net.Address.initIp6(addr_buff, 0, 0, 0);
|
addr = std.net.Address.initIp6(addr_buff, 0, 0, @intCast(std.c.if_nametoindex(ip_info.interface.?)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (addr == null) {
|
if (addr == null) {
|
||||||
return MDNSError.NoMatchingAddress;
|
return MDNSError.NoMatchingAddress;
|
||||||
}
|
}
|
||||||
return switch (ip_info) {
|
return switch (ip_info.version) {
|
||||||
.IPv4 => util.IP{ .v4 = addr },
|
.IPv4 => util.IP{ .v4 = addr },
|
||||||
.IPv6 => util.IP{ .v6 = addr },
|
.IPv6 => util.IP{ .v6 = addr },
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
|
|
23
src/util.zig
23
src/util.zig
|
@ -6,11 +6,13 @@ const ArgError = error{
|
||||||
NotEnoughArgs,
|
NotEnoughArgs,
|
||||||
BadDomain,
|
BadDomain,
|
||||||
InvalidAddressVer,
|
InvalidAddressVer,
|
||||||
|
InterfaceRequired,
|
||||||
|
InvalidInterface,
|
||||||
EnvVarNotSet,
|
EnvVarNotSet,
|
||||||
InvalidOldHostsPath,
|
InvalidOldHostsPath,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const IP_VER = enum(u3) {
|
pub const IP_VER_ENUM = enum(u3) {
|
||||||
Both = 0,
|
Both = 0,
|
||||||
IPv4 = 4,
|
IPv4 = 4,
|
||||||
IPv6 = 6,
|
IPv6 = 6,
|
||||||
|
@ -28,6 +30,11 @@ pub fn merge_addrs(v4: IP, v6: IP) IP {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const IPInfo = struct {
|
||||||
|
version: IP_VER_ENUM,
|
||||||
|
interface: ?[:0]const u8,
|
||||||
|
};
|
||||||
|
|
||||||
pub const Domain = struct {
|
pub const Domain = struct {
|
||||||
name: [:0]const u8,
|
name: [:0]const u8,
|
||||||
labels: [5][]const u8,
|
labels: [5][]const u8,
|
||||||
|
@ -46,7 +53,7 @@ pub const cwd = std.fs.cwd();
|
||||||
|
|
||||||
pub fn get_input() !struct {
|
pub fn get_input() !struct {
|
||||||
Domain,
|
Domain,
|
||||||
IP_VER,
|
IPInfo,
|
||||||
} {
|
} {
|
||||||
var args = std.process.args();
|
var args = std.process.args();
|
||||||
_ = args.next(); // consume calling binary arg
|
_ = args.next(); // consume calling binary arg
|
||||||
|
@ -55,9 +62,17 @@ pub fn get_input() !struct {
|
||||||
const domain = try check_domain(domain_str);
|
const domain = try check_domain(domain_str);
|
||||||
|
|
||||||
const ip_ver_str = args.next() orelse return ArgError.NotEnoughArgs;
|
const ip_ver_str = args.next() orelse return ArgError.NotEnoughArgs;
|
||||||
const ip_ver = std.meta.intToEnum(IP_VER, std.fmt.parseInt(u3, ip_ver_str, 10) catch return ArgError.InvalidAddressVer) catch return ArgError.InvalidAddressVer;
|
const ip_ver = std.meta.intToEnum(IP_VER_ENUM, std.fmt.parseInt(u3, ip_ver_str, 10) catch return ArgError.InvalidAddressVer) catch return ArgError.InvalidAddressVer;
|
||||||
|
|
||||||
return .{ domain, ip_ver };
|
var iface: ?[:0]const u8 = null;
|
||||||
|
if (ip_ver != IP_VER_ENUM.IPv4) {
|
||||||
|
iface = args.next() orelse return ArgError.InterfaceRequired;
|
||||||
|
if (std.c.if_nametoindex(iface.?) == 0) {
|
||||||
|
return ArgError.InvalidInterface;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{ domain, IPInfo{ .version = ip_ver, .interface = iface } };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_domain(domain_str: [:0]const u8) !Domain {
|
fn check_domain(domain_str: [:0]const u8) !Domain {
|
||||||
|
|
Loading…
Reference in a new issue