Added more descriptive error messages for TLS certificate verification
failures across DoH, DoT, DoQ, and DoH3 protocols. The error messages
now include:
- Certificate subject information
- Issuer organization details
- Common name of the certificate
This helps users and developers better understand certificate validation
failures by providing specific details about the untrusted certificate,
rather than just a generic "unknown authority" message.
Example error message change:
Before: "certificate signed by unknown authority"
After: "certificate signed by unknown authority: TestCA, TestOrg, TestIssuerOrg"
Fixes search domains not being preserved when the resolv.conf file is
reverted to its previous state. This ensures that important domain
search configuration is maintained during DNS configuration changes.
The search domains handling was missing in setResolvConf function,
which is responsible for restoring DNS settings.
Changed the IPv6 support detection to try multiple common ports (HTTP/HTTPS) instead of
just testing against a DNS port. The function now returns both the IPv6 support status
and the successful port that confirmed the connectivity. This makes the IPv6 detection
more reliable by not depending solely on DNS port availability.
Previously, the function only tested connectivity to a DNS port (53) over IPv6.
Now it tries to connect to commonly available ports like HTTP (80) and HTTPS (443)
until it finds a working one, making the detection more robust in environments where
certain ports might be blocked.
For cached or singleflight messages, the edns0 cookie is currently
shared among all of them, causing mismatch cookie warning from clients.
The ctrld proxy should re-set client cookies for each request
separately, even though they use the same shared answer.
To guard ctrld from possible DoS to remote upstreams, this commit
implements following things:
- Optimizing multiple queries with the same domain and qtype to use
singleflight group, so there's only 1 query to remote upstreams at
any time.
- Adding a hot cache with 1 second TTL, so repeated queries will re-use
the result from cache if existed, preventing unnecessary requests to
remote upstreams.
There's a bug in wmi library which causes race condition when getting
wmi instance manager concurrently. The new tests for setup bootstrap ip
concurrently thus failed unexpectedly.
There's going to be a fix sent to the upstream, in the meantime, disable
the parallel test temporary.
See: https://github.com/microsoft/wmi/issues/165
As part of v1.4.0 release, reading DNS from /etc/resolv.conf file is
only available for Macos. However, there's no reason to prevent this
function from working on other *nix systems.
This commit unify the function to *nix, so it could be added as DNS
source for Linux and Freebsd.
So on system where there's no available DNS, non-ControlD upstreams
could be bootstrapped like before.
While at it, also improving lookupIP to not initializing OS resolver
anymore, removing the un-necessary contention for accquiring/releasing
OS resolver mutex.
If the socket file does not exist, it means that "ctrld start" was never
run. In this case, the warning message should not be printed to avoid
needless confusion.
Generally, using /jffs/scripts/dnsmasq.postconf is the right way to add
custom configuration to dnsmasq on Merlin. However, we have seen many
reports that the postconf does not work on their devices.
This commit changes how dnsmasq config manipulation is done on Merlin,
so it's expected to work on all Merlin devices:
- Writing /jffs/scripts/dnsmasq.postconf script
- Copy current dnsmasq.conf to /jffs/configs/dnsmasq.conf
- Run postconf script directly on /jffs/configs/dnsmasq.conf
- Restart dnsmasq
This way, the /jffs/configs/dnsmasq.conf will contain both current
dnsmasq config, and also custom config added by ctrld, without worrying
about conflicting, because configuration was added by postconf.
See (1) for more details about custom config files on Merlin.
(1) https://github.com/RMerl/asuswrt-merlin.ng/wiki/Custom-config-files
So using "ctrld stop" or service manager to stop ctrld will end up with
the same result, stopped ctrld with a working DNS, and deactivation pin
code will always have effects if set.
Since requests are mostly originated from the machine itself, so all
necessary metadata is local to it.
Currently, the desktop platforms are Windows desktop and darwin.
netmon provides ipv6 availability during network event changes, so use
this metadata instead of wasting on polling check.
Further, repeated network errors will force marking ipv6 as disable if
were being enabled, catching a rare case when ipv6 were disabled from
cli or system settings.
Currently, custom config is only validated against invalid syntax, not
the validating rules for each configuration value. It causes ctrld
process fatal instead of disregarding as expected.
To fix this, force the validating rule after fetching remote config.
While at it, also add the default network value if non-existed.
When ctrld performs upgrading tasks, the current binary would be moved
to different file, thus the executable will return this new file name,
instead of the old "/path/to/ctrld".
The config path on FreshTomato is located in the same directory with
ctrld binary, with ".startup" suffix. So when the binary was moved
during upgrading, the config path is located wrongly.
To fix it, read the binary path from service config first, then only
fallback to the current executable if the path is empty (this is the
same way ctrld is doing for other router platforms).
So the "ctrld start" should know earlier that "ctrld run" failed to
listen on certain port, and terminate earlier instead of waiting for
timeout happened.
Since application may need SRV record for public domains, which could be
blocked by OS resolver, but not with remote upstreams.
This was reported by a Minecraft user, who seeing thing is broken after
upgrading to v1.4.0 release.
The log ip connection may be nil, since it was not created if blocked by
firewall/VPN apps.
While at it, also add warning when the ipc connection could not be created.
Currently, ctrld requires the default route interface existed to be
functional correctly.
However, on systems where default route is non existed, or point to a
virtual interface (like ipsec based VPN), the fact that the OS is using
this interface as default gateway and doesn't actually send things to
127.0.0.1 is not ctrld's problem.
In this case, ctrld should just start normally, without worrying about
the no default route interface problem.
The runtime internal log should be initialized right after normal log
from configuration, prevent missing log from any actions that could be
happened between two initializations.
For partial init log data (does not end with a newline), the log writer
discard data after the last newline to make the log prettier, then write
the init end marker. This causes the marker could be written more than
once, since the second overflows will preserve the data which does
include the marker from the first write.
To fix this, ensure that the init end marker is only written once, and
the second overflows will preserve data until the marker instead of the
fixed initial size like the first one.
linux/amd64 have the nocgo binary to support system where standard libc
missing.
If the current binary is a nocgo version, "ctrld upgrade" command must
honor the nocgo setting and download the right binary.
openwrt 24.10 changes the dnsmasq default config path, causing breaking
changes to softwares which depends on old behavior.
This commit adds a workaround for the issue, by querying the actual
config directory from ubus service list, instead of relying on the
default hardcode one.
Currently, the router discovers initialization are done during startup.
If it were failed, the discovers are skipped. This is too strict, since
the initialization could be failed due to some requires services are not
ready when ctrld started, or router specific requirements for services
management during startup (like UnifiOS v4.0.20).
To fix this, ctrld should relax the initialization checking, allow it to
be failed, and still use the discovers later.
Because ctrld needs to query custom client mapping from it.
While at it, also make the error message clearer when initializing ubios
discover failed, by attaching the command output to returned error.
In case of remote config validation error during start, it's likely that
there's problem with connecting to ControlD API. The ctrld daemon was
restarted in this case, but may not ready to receive requests yet.
This commit changes the error message to explicitly state that instead
of a mis-leading "could not complete service restart".
Previously, a valid interfaces map is only meaningful on Windows and
Darwin, where ctrld needs to set DNS for all physical interfaces.
With new network monitor, the valid interfaces is used for checking new
changes, thus we have to implement the valid interfaces map for all
systems.
- On Linux, just retrieving all non-virtual interfaces.
- On others, fallback to use default route interface only.
The ProxyLogger must only be set after mainLog is fully initialized.
However, it's being set before the final initialization of mainlog,
causing it still refers to stale old pointer.
To fix this, introduce a new function to discard ProxyLogger explicitly,
and use this function to init logging for all interactive commands.
By using existed package instead of hand written one.
While at it, also simplifying the logger getter, since the ProxyLogger
is guaranted to be non-nil.
By recording both the error and output of external commands.
While at it:
- Removing un-necessary usages of sudo, since ctrld already
running with root privilege.
- Removing un-used function triggerCaptiveCheck.
So these events will be recorded separately from normal runtime log,
making troubleshooting later more easily.
While at it, only update ctrld.ProxyLogger for runCmd, it's the only one
which needs to log the query when proxying requests.
For normal OS resolver, ctrld does not use local addresses as nameserver
to avoid possible looping. However, on AD environment with local DNS
running, AD queries must be sent to the local DNS server for proper
resolving.
By getting the name property directly from adapter instance, instead of
using net.InterfaceByIndex function, which could return an error when
the adapter is disabled.
Since these are the interfaces that ctrld will manipulate anyway.
While at it, also skipping non-working devices on MacOS, by checking
if the device is present in network service order
Since ctrld process does not rely on the global variable iface anymore
during runtime, ctrld client's operations must be updated to reflect
this change, too.
The current flow involves marking OS resolver as down, which is not
right at all, since ctrld depends on it for leaking queries.
This commits implements new flow, which ctrld will restore DNS settings
once leaking marked, allowing queries go to OS resolver until the
internet connection is established.
Without verbose log, we use internal log writer with log level set to
debug. However, this will affect other writers, like console log, since
they are default to notice level.
By adopting FilteredLevelWriter, we can make internal log writer run in
debug level, but all others will run in default level instead.