aboutsummaryrefslogtreecommitdiff
path: root/core/net
diff options
context:
space:
mode:
authorJeroen van Rijn <Kelimion@users.noreply.github.com>2025-01-27 22:55:48 +0100
committerJeroen van Rijn <Kelimion@users.noreply.github.com>2025-01-27 22:55:48 +0100
commit8998d74a926f52ef02a8f77936922dae3da6085f (patch)
tree8a58020f914c2c20791b9b818f99587659e7e4a2 /core/net
parentd85c2c1ca7d73c5f0513c731a13c80116124b9e4 (diff)
Add mDNS for *nix.
Diffstat (limited to 'core/net')
-rw-r--r--core/net/common.odin1
-rw-r--r--core/net/dns.odin89
2 files changed, 88 insertions, 2 deletions
diff --git a/core/net/common.odin b/core/net/common.odin
index 64155313d..12add8225 100644
--- a/core/net/common.odin
+++ b/core/net/common.odin
@@ -149,6 +149,7 @@ IP4_Any := IP4_Address{}
IP6_Any := IP6_Address{}
IP4_mDNS_Broadcast := Endpoint{address=IP4_Address{224, 0, 0, 251}, port=5353}
+IP6_mDNS_Broadcast := Endpoint{address=IP6_Address{65282, 0, 0, 0, 0, 0, 0, 251}, port = 5353}
Endpoint :: struct {
address: Address,
diff --git a/core/net/dns.odin b/core/net/dns.odin
index ffb97fc5b..b3649c686 100644
--- a/core/net/dns.odin
+++ b/core/net/dns.odin
@@ -132,7 +132,14 @@ resolve_ip4 :: proc(hostname_and_maybe_port: string) -> (ep4: Endpoint, err: Net
return
}
case Host:
- recs, _ := get_dns_records_from_os(t.hostname, .IP4, context.temp_allocator)
+ recs: []DNS_Record
+
+ if ODIN_OS != .Windows && strings.has_suffix(t.hostname, ".local") {
+ recs, _ = get_dns_records_from_mdns(t.hostname, .IP4, context.temp_allocator)
+ } else {
+ recs, _ = get_dns_records_from_os(t.hostname, .IP4, context.temp_allocator)
+ }
+
if len(recs) == 0 {
err = .Unable_To_Resolve
return
@@ -159,7 +166,14 @@ resolve_ip6 :: proc(hostname_and_maybe_port: string) -> (ep6: Endpoint, err: Net
return t, nil
}
case Host:
- recs, _ := get_dns_records_from_os(t.hostname, .IP6, context.temp_allocator)
+ recs: []DNS_Record
+
+ if ODIN_OS != .Windows && strings.has_suffix(t.hostname, ".local") {
+ recs, _ = get_dns_records_from_mdns(t.hostname, .IP6, context.temp_allocator)
+ } else {
+ recs, _ = get_dns_records_from_os(t.hostname, .IP6, context.temp_allocator)
+ }
+
if len(recs) == 0 {
err = .Unable_To_Resolve
return
@@ -283,6 +297,77 @@ get_dns_records_from_nameservers :: proc(hostname: string, type: DNS_Record_Type
return
}
+get_dns_records_from_mdns :: proc(hostname: string, type: DNS_Record_Type, allocator := context.allocator) -> (records: []DNS_Record, err: DNS_Error) {
+ assert(type == .IP4 || type == .IP6)
+
+ context.allocator = allocator
+
+ if !validate_hostname(hostname) {
+ return nil, .Invalid_Hostname_Error
+ }
+
+ hdr := DNS_Header{
+ id = 0,
+ is_response = false,
+ opcode = 0,
+ is_authoritative = false,
+ is_truncated = false,
+ is_recursion_desired = true,
+ is_recursion_available = false,
+ response_code = DNS_Response_Code.No_Error,
+ }
+
+ id, bits := pack_dns_header(hdr)
+ dns_hdr := [6]u16be{}
+ dns_hdr[0] = id
+ dns_hdr[1] = bits
+ dns_hdr[2] = 1
+
+ dns_query := [2]u16be{ u16be(type), 1 }
+
+ output := [(size_of(u16be) * 6) + NAME_MAX + (size_of(u16be) * 2)]u8{}
+ b := strings.builder_from_slice(output[:])
+
+ strings.write_bytes(&b, mem.slice_data_cast([]u8, dns_hdr[:]))
+ ok := encode_hostname(&b, hostname)
+ if !ok {
+ return nil, .Invalid_Hostname_Error
+ }
+ strings.write_bytes(&b, mem.slice_data_cast([]u8, dns_query[:]))
+
+ dns_packet := output[:strings.builder_len(b)]
+
+ dns_response_buf := [4096]u8{}
+ dns_response: []u8
+
+ name_server := IP4_mDNS_Broadcast if type == .IP4 else IP6_mDNS_Broadcast
+
+ conn, sock_err := make_unbound_udp_socket(family_from_endpoint(name_server))
+ if sock_err != nil {
+ return nil, .Connection_Error
+ }
+ defer close(conn)
+
+ send(conn, dns_packet[:], name_server)
+
+ if set_option(conn, .Receive_Timeout, time.Second * 1) != nil {
+ return nil, .Connection_Error
+ }
+
+ recv_sz, _, _ := recv_udp(conn, dns_response_buf[:])
+ if recv_sz == 0 {
+ return nil, .Server_Error
+ }
+
+ dns_response = dns_response_buf[:recv_sz]
+
+ rsp, _ok := parse_response(dns_response, type)
+ if !_ok {
+ return nil, .Server_Error
+ }
+ return rsp[:], nil
+}
+
// `records` slice is also destroyed.
destroy_dns_records :: proc(records: []DNS_Record, allocator := context.allocator) {
context.allocator = allocator