diff --git a/core/net/common.odin b/core/net/common.odin index 263fc770f..12add8225 100644 --- a/core/net/common.odin +++ b/core/net/common.odin @@ -95,6 +95,7 @@ Resolve_Error :: enum u32 { } DNS_Error :: enum u32 { + None = 0, Invalid_Hostname_Error = 1, Invalid_Hosts_Config_Error, Invalid_Resolv_Config_Error, @@ -147,6 +148,9 @@ IP6_Loopback :: IP6_Address{0, 0, 0, 0, 0, 0, 0, 1} 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, port: int, diff --git a/core/net/dns.odin b/core/net/dns.odin index ffb97fc5b..6d5dfea23 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_nameservers(t.hostname, .IP4, {IP4_mDNS_Broadcast}, nil, 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_nameservers(t.hostname, .IP6, {IP6_mDNS_Broadcast}, nil, 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 @@ -255,12 +269,6 @@ get_dns_records_from_nameservers :: proc(hostname: string, type: DNS_Record_Type return nil, .Connection_Error } - // recv_sz, _, recv_err := recv_udp(conn, dns_response_buf[:]) - // if recv_err == UDP_Recv_Error.Timeout { - // continue - // } else if recv_err != nil { - // continue - // } recv_sz, _ := recv_udp(conn, dns_response_buf[:]) or_continue if recv_sz == 0 { continue diff --git a/core/net/dns_windows.odin b/core/net/dns_windows.odin index 2f3831767..7736851b8 100644 --- a/core/net/dns_windows.odin +++ b/core/net/dns_windows.odin @@ -29,9 +29,14 @@ import win "core:sys/windows" _get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator := context.allocator) -> (records: []DNS_Record, err: DNS_Error) { context.allocator = allocator + options := win.DNS_QUERY_OPTIONS{} + if strings.has_suffix(hostname, ".local") { + options = {.MULTICAST_ONLY, .MULTICAST_WAIT} // 0x00020500 + } + host_cstr := strings.clone_to_cstring(hostname, context.temp_allocator) rec: ^win.DNS_RECORD - res := win.DnsQuery_UTF8(host_cstr, u16(type), 0, nil, &rec, nil) + res := win.DnsQuery_UTF8(host_cstr, u16(type), options, nil, &rec, nil) switch u32(res) { case 0: diff --git a/core/net/socket_linux.odin b/core/net/socket_linux.odin index b7816b0b6..cafec747d 100644 --- a/core/net/socket_linux.odin +++ b/core/net/socket_linux.odin @@ -35,6 +35,7 @@ Socket_Option :: enum c.int { Send_Buffer_Size = c.int(linux.Socket_Option.SNDBUF), Receive_Timeout = c.int(linux.Socket_Option.RCVTIMEO), Send_Timeout = c.int(linux.Socket_Option.SNDTIMEO), + Broadcast = c.int(linux.Socket_Option.BROADCAST), } // Wrappers and unwrappers for system-native types @@ -337,7 +338,8 @@ _set_option :: proc(sock: Any_Socket, option: Socket_Option, value: any, loc := .Reuse_Address, .Keep_Alive, .Out_Of_Bounds_Data_Inline, - .TCP_Nodelay: + .TCP_Nodelay, + .Broadcast: // TODO: verify whether these are options or not on Linux // .Broadcast, <-- yes // .Conditional_Accept, diff --git a/core/sys/windows/dnsapi.odin b/core/sys/windows/dnsapi.odin index 4fd9f7a19..728813696 100644 --- a/core/sys/windows/dnsapi.odin +++ b/core/sys/windows/dnsapi.odin @@ -5,6 +5,6 @@ foreign import "system:Dnsapi.lib" @(default_calling_convention="system") foreign Dnsapi { - DnsQuery_UTF8 :: proc(name: cstring, type: u16, options: DWORD, extra: PVOID, results: ^^DNS_RECORD, reserved: PVOID) -> DNS_STATUS --- + DnsQuery_UTF8 :: proc(name: cstring, type: u16, options: DNS_QUERY_OPTIONS, extra: PVOID, results: ^^DNS_RECORD, reserved: PVOID) -> DNS_STATUS --- DnsRecordListFree :: proc(list: ^DNS_RECORD, options: DWORD) --- } diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index ab79c682a..8069659c9 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -4576,6 +4576,31 @@ DNS_SRV_DATAA :: struct { _: WORD, // padding } +// See https://learn.microsoft.com/en-us/windows/win32/dns/dns-constants +DNS_QUERY_OPTION :: enum DWORD { + ACCEPT_TRUNCATED_RESPONSE = 0, + DNS_QUERY_USE_TCP_ONLY = 1, + NO_RECURSION = 2, + BYPASS_CACHE = 3, + NO_WIRE_QUERY = 4, + NO_LOCAL_NAME = 5, + NO_HOSTS_FILE = 6, + NO_NETBT = 7, + WIRE_ONLY = 8, + RETURN_MESSAGE = 9, + MULTICAST_ONLY = 10, + NO_MULTICAST = 11, + TREAT_AS_FQDN = 12, + ADDRCONFIG = 13, + DUAL_ADDR = 14, + MULTICAST_WAIT = 17, + MULTICAST_VERIFY = 18, + DONT_RESET_TTL_VALUES = 20, + DISABLE_IDN_ENCODING = 21, + APPEND_MULTILABEL = 23, +} +DNS_QUERY_OPTIONS :: bit_set[DNS_QUERY_OPTION; DWORD] + SOCKADDR :: struct { sa_family: ADDRESS_FAMILY, sa_data: [14]CHAR,