Skip to content

Commit

Permalink
Use resolv.conf to find name servers on Posix (#1394)
Browse files Browse the repository at this point in the history
* Use resolv.conf to find name servers on Posix

* Fix doc comment

* Fix Windows

* Robustify resolv.conf parser

* Feedback
  • Loading branch information
Erik Corry authored Feb 2, 2023
1 parent 2a6de96 commit 311706a
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 5 deletions.
63 changes: 58 additions & 5 deletions lib/net/modules/dns.toit
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ dns_lookup -> net.IpAddress
if not server:
client = default_client
else:
client = ALL_CLIENTS_.get server --init=:
client = AUTO_CREATED_CLIENTS_.get server --init=:
DnsClient [server]
return client.get host --accept_ipv4=accept_ipv4 --accept_ipv6=accept_ipv6 --timeout=timeout

Expand All @@ -53,11 +53,64 @@ DEFAULT_CLIENT ::= DnsClient [
]

// A map from IP addresses (in string form) to DNS clients.
// If a DNS client has multiple servers it can query then they
// are separated by slash (/) in the key.
ALL_CLIENTS_ ::= {DEFAULT_CLIENT.servers_.join "/": DEFAULT_CLIENT}
AUTO_CREATED_CLIENTS_ ::= {:}

default_client := DEFAULT_CLIENT
user_set_client_/DnsClient? := null
dhcp_client_/DnsClient? := null

RESOLV_CONF_ ::= "/etc/resolv.conf"

/**
On Unix systems the default client is one that keeps an eye on changes in
/etc/resolv.conf.
On FreeRTOS systems the default client is set by DHCP.
On Windows we currently default to using Google and Cloudflare DNS servers.
On all platforms you can set a custom default client with the
$(default_client= client) setter.
*/
default_client -> DnsClient:
if user_set_client_: return user_set_client_
if platform == PLATFORM_FREERTOS and dhcp_client_: return dhcp_client_
if platform == PLATFORM_LINUX or platform == PLATFORM_MACOS: return etc_resolv_client_
return DEFAULT_CLIENT

default_client= client/DnsClient? -> none:
user_set_client_ = client

current_etc_resolv_client_/DnsClient? := null
etc_resolv_update_time_/Time? := null

etc_resolv_client_ -> DnsClient:
catch --trace:
resolv_conf_stat := stat_ RESOLV_CONF_ true
etc_stat := stat_ "/etc" true
resolv_conf_time := Time.epoch --ns=resolv_conf_stat[ST_MTIME_]
etc_time := Time.epoch --ns=etc_stat[ST_MTIME_]
modification_time := resolv_conf_time > etc_time ? resolv_conf_time : etc_time
if etc_resolv_update_time_ == null or etc_resolv_update_time_ < modification_time:
etc_resolv_update_time_ = modification_time
// Create a new client from resolv.conf.
resolv_conf := (read_file_content_posix_ RESOLV_CONF_ resolv_conf_stat[ST_SIZE_]).to_string
nameservers := []
resolv_conf.split "\n": | line |
hash := line.index_of "#"
if hash >= 0: line = line[..hash]
line = line.trim
if line.starts_with "nameserver ":
server := line[11..].trim
if net.IpAddress.is_valid server --accept_ipv4=true --accept_ipv6=false:
nameservers.add server
current_etc_resolv_client_ = DnsClient nameservers
return current_etc_resolv_client_ or DEFAULT_CLIENT

ST_SIZE_ ::= 7
ST_MTIME_ ::= 9

stat_ name/string follow_links/bool -> List?:
#primitive.file.stat

read_file_content_posix_ filename/string size/int -> ByteArray:
#primitive.file.read_file_content_posix

CLASS_INTERNET ::= 1

Expand Down
1 change: 1 addition & 0 deletions src/compiler/propagation/type_primitive_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ TYPE_PRIMITIVE_ANY(mkdtemp)
TYPE_PRIMITIVE_ANY(is_open_file)
TYPE_PRIMITIVE_ANY(realpath)
TYPE_PRIMITIVE_ANY(cwd)
TYPE_PRIMITIVE_BYTE_ARRAY(read_file_content_posix)

} // namespace toit::compiler
} // namespace toit
1 change: 1 addition & 0 deletions src/primitive.h
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,7 @@ namespace toit {
PRIMITIVE(is_open_file, 1) \
PRIMITIVE(realpath, 1) \
PRIMITIVE(cwd, 0) \
PRIMITIVE(read_file_content_posix, 2) \

#define MODULE_PIPE(PRIMITIVE) \
PRIMITIVE(init, 0) \
Expand Down
26 changes: 26 additions & 0 deletions src/primitive_file_posix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,32 @@ Object* return_open_error(Process* process, int err) {
OTHER_ERROR;
}

PRIMITIVE(read_file_content_posix) {
#ifndef TOIT_POSIX
UNIMPLEMENTED_PRIMITIVE;
#else
ARGS(cstring, filename, int, file_size);
ByteArray* result = process->allocate_byte_array(file_size);
if (result == null) ALLOCATION_FAILED;
ByteArray::Bytes result_bytes(result);
int fd = open(filename, O_RDONLY);
if (fd == -1) return return_open_error(process, errno);
int position = 0;
for (position = 0; position < file_size; ) {
int n = read(fd, result_bytes.address() + position, file_size - position);
if (n == -1) {
if (errno == EINTR) continue;
close(fd);
OTHER_ERROR;
}
if (n == 0) INVALID_ARGUMENT; // File changed size?
position += n;
}
close(fd);
return result;
#endif
}

// Coordinate with utils.toit.
static const int FILE_RDONLY = 1;
static const int FILE_WRONLY = 2;
Expand Down
5 changes: 5 additions & 0 deletions src/primitive_file_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,11 @@ PRIMITIVE(cwd) {
return result;
}

PRIMITIVE(read_file_content_posix) {
// This is currenly only used for /etc/resolv.conf.
UNIMPLEMENTED_PRIMITIVE;
}

}

#endif // TOIT_WINDOWS.

0 comments on commit 311706a

Please sign in to comment.