On some platforms, like pfsense, ntpd is not problem, so do not spawn
the DNS server for it, which may conflict with default DNS server.
While at it, also make sure that ctrld will be run at last on startup.
On DD-WRT v3.0-r52189, dnsmasq version 2.89 lease format looks like:
1685794060 <mac> <ip> <hostname> 00:00:00:00:00:04 9
It has 6 fields, while the current parser only looks for line with exact
5 fields, which is too restricted. In fact, the parser shold just skip
line with less than 4 fields, because the 4th field is the hostname,
which is the last client info that ctrld needs.
Currently, on routers that require NTP waiting, ctrld makes the cleanup
process, and restart dnsmasq for restoring default DNS config, so ntpd
can query the NTP servers. It did work, but the code will depends on
router platforms.
Instead, we can spawn a plain DNS listener before PreRun on routers,
this listener will serve NTP dns queries and once ntp is configured, the
listener is terminated and ctrld will start serving using its configured
upstreams.
While at it, also fix the userHomeDir function on freshtomato, which
must return the binary directory for routers that requires JFFS.
In commit 670879d1, the backoff is changed to be passed a real error,
instead of a place holder. However, the test query may return a failed
response with a nil error, causing the backoff never fire.
Fixing this by ensuring the error is wrapped, so the backoff always see
a non-nil error.
On WSL 1, the routing table do not contain default route, causing ctrld
failed to get the default iface for setting DNS. However, WSL 1 only use
/etc/resolv.conf for setting up DNS, so the interface does not matter,
because the setting is applied global anyway.
To fix it, just return "lo" as the default interface name on WSL 1.
While at it, also removing the useless service.Logger call, which is not
unified with the current logger, and may cause false positive on system
where syslog is not configured properly (like WSL 1).
Also passing the real error when doing sel-check to backoff, so we don't
have to use a place holder error.
In split mode, the code must check for ipv6 availability to return the
correct network stack. Otherwise, we may end up using "tcp6-tls" even
though the upstream IP is an ipv4.
The assignment is changed wrongly in process of refactoring parallel
dialer for resolving bootstrap IP.
While at it, also satisfy staticheck for jffs not enabled error.
On some Merlin routers, the time is broken when system reboot, and need
to wait for NTP synced to get the correct time. For fetching API in cd
mode successfully, ctrld need to wait until NTP set the time correctly,
otherwise, the certificate validation would complain.
On some Merlin routers, due to ntp bug, after rebooing, dnsmasq config
was restored to default without ctrld changes, causing ctrld stop
working. Workaround this problem by catching restart diskmon event,
which is triggered by ntpd_synced, then restart dnsmasq.
When bootstrapping, if the network changed, for example, firewall rules
changed during VPN connection, the bootstrap IPs may not be resolved, so
ctrld won't work. Since bootstrap IPs is necessary for ctrld to work
properly, we should wait until we can resolve upstream IP before we can
start serving requests.
Instead of always doubling the request, first we wrap the request with a
failover timeout, 500ms, which is an average time for a normal request.
If this request failed, trigger re-bootstrapping and retry the request.
When network changes, for example: connect/disconnect VPN, the old
connection will become broken, but still can be re-used for new
requests. That would cause un-necessary delay for ctrld clients:
- Time 0 - do request with broken transport, 5s timeout.
- Time 0.5 - network stack become usable.
- Time 5 - timeout reached.
- Time 5.1 - do request with new transport -> success.
Instead, we can do two requests in parallel, with the failover one using
a fresh new transport. So if the main one is broken, we still can get
the result from the failover one.
We see in practice on fresh new VM test, there's a DNS server that
return the answer with record not for the query domain.
To workaround this, filter out the answers not for the query domain.
This reverts commit 00fe7f59d13774f2ea6c325bdbb8165be58a1edd.
The purpose is disable cd mode for already installed service, which is
a hard problem than we thought. So leave it out of v1.2 cycle.
When writing default config file, the content must be marshalled to the
config object first before writing to disk.
While at it, also use full path for default config file to make it clear
to the user where the config is written.
This commit add the ability for ctrld to gather client information,
including mac/ip/hostname, and send to Control-D server through a
config per upstream.
- Add send_client_info upstream config.
- Read/Watch dnsmasq leases files on supported platforms.
- Add corresponding client info to DoH query header
All of these only apply for Control-D upstream, though.
So we don't have to depend on network stack probing to decide whether
ipv4 or ipv6 will be used.
While at it, also prevent a race report when doing the same parallel
resolving for os resolver, even though this race is harmless.
Otherwise, we experiment with ctrld slow start after rebooting, because
the network check continuously report failed status even the network
state is up. Restoring the DNS before stopping, we leave the network
state as default, as long as ctrld starts, the DNS is configured again.
The bootstrap process has two issues that can make ctrld stop resolving
after restarting machine host.
ctrld uses bootstrap DNS and os nameservers for resolving upstream. On
unix, /etc/resolv.conf content is used to get available nameservers.
This works well when installing ctrld. However, after being installed,
ctrld may modify the content of /etc/resolv.conf itself, to make other
apps use its listener as DNS resolver. So when ctrld starts after OS
restart, it ends up using [bootstrap DNS + ctrld's listener], for
resolving upstream. At this moment, if ctrld could not contact bootstrap
DNS for any reason, upstream domain will not be resolved.
For above reason, an upstream may not have bootstrap IPs after ctrld
starts. When re-bootstrapping, if there's no bootstrap IPs, ctrld should
call the setup bootstrap process again. Currently, it does not, causing
all queries failed.
This commit fixes above issue by adding mechanism for retrieving OS
nameservers properly, by querying routing table information:
- Parsing /proc/net subsystem on Linux.
- For BSD variants, just fetching routing information base from OS.
- On Windows, just include the gateway information when reading iface.
The fixing for second issue is trivial, just kickoff a bootstrap process
if there's no bootstrap IPs when re-boostrapping.
While at it, also ensure that fetching resolver information from
ControlD API is also used the same approach.
Fixes#34
For os resolver, ctrld queries against all servers concurrently, and get
the first success result back. However, if all server failed, the result
channel is not closed, causing ctrld hang.
Fixing this by closing the result channel once getting back all response
from servers.
While at it, also shorten the backoff time when waiting for network up,
ctrld should serve as fast as possible after network is available.
Updates #34
- Include version/OS information when logging
- Make time field human readable in log file
- Force root privilege when running status command on darwin
Updates #34
When startup, ctrld waits for network up before calling s.Run to starts
its logic. However, if network is down on startup, ctrld will hang on
waiting for network up. That causes OS service manager unhappy, as ctrld
do not response to it, marking ctrld as failure service and never start
ctrld again.
To fix this, we should call s.Run as soon as possible, and use a channel
for waiting a signal that we can actual do our logic after network up.
Update #34
Avoiding reading/writing global config, causing a data race. While at
it, also guarding read/write access to cfg.Service.AllocateIP field,
since when it is read/write by multiple goroutines.
We only need on demand information when re-bootstrapping. On Bootsrap,
this is already checked by ctrldnet.Up, so on demand query will cause
un-necessary slow down if external ipv6 is slow to response.
On Windows host with StarLink network, ctrld hangs on startup for ~30s
before continue running. This dues to IPv6 is configured but no external
IPv6 can be reached. When probing stack, ctrld is dialing using ipv6
without any timeout set, so the dialing timeout is enforced by OS.
This commit adds a timeout for probing dialer, so we ensure the probing
process will fail fast.