Skip to content

LLT-7558: Domain accessible after being removed from whitelist - #1931

Open
tomaszpatejko wants to merge 3 commits into
mainfrom
LLT-7558-blocking-unblocking-domain-doesnt-work
Open

LLT-7558: Domain accessible after being removed from whitelist#1931
tomaszpatejko wants to merge 3 commits into
mainfrom
LLT-7558-blocking-unblocking-domain-doesnt-work

Conversation

@tomaszpatejko

@tomaszpatejko tomaszpatejko commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Problem

Domain is still accessible after it has been removed from whitelist.
The following use case trigger the bug:

  1. Enable libtelio with libfirewall;
  2. Try to access a domain. Whitelist is empty initially so the DNS query is sent to the blocking TP-Lite DNS server. The query result is NXDOMAIN that indicates that the domain is blocked.
  3. Whitelist the domain. Nonblocking DNS server responds with an IP address that is cached in DNS resolver cache.
  4. Reblock the domain by clearing the whitelist with an empty domain list.
  5. Try to access the domain again. Bug: the IP address is served from resolver cache that was written is step 3. Expected behaviour should be that blocking TP-Lite DNS server is queried for an IP address and response should be NXDOMAIN.

Solution

Flush DNS resolver's cache when whitelist is set. This was no stale cache entries will be present and correct TP-Lite DNS server with be consulted for blocked domain's IP address.

AI disclosure: Claude was used for the following:

  • log analysis and rootcausing,
  • natlab test generation,
  • fix suggestion and generation.

The work was also human-reviewed.

☑️ Definition of Done checklist

  • Commit history is clean (requirements)
  • README.md is updated
  • Functionality is covered by unit or integration tests

@tomaszpatejko
tomaszpatejko requested a review from a team as a code owner August 5, 2026 12:10
@tomaszpatejko
tomaszpatejko force-pushed the LLT-7558-blocking-unblocking-domain-doesnt-work branch from e2bf5c3 to 67bc7b1 Compare August 7, 2026 10:53
@tomaszpatejko
tomaszpatejko force-pushed the LLT-7558-blocking-unblocking-domain-doesnt-work branch from 104cba8 to 60cccb8 Compare August 11, 2026 13:51
@tomaszpatejko
tomaszpatejko force-pushed the LLT-7558-blocking-unblocking-domain-doesnt-work branch from 60cccb8 to df9c55a Compare August 11, 2026 14:02
@tomaszpatejko
tomaszpatejko force-pushed the LLT-7558-blocking-unblocking-domain-doesnt-work branch from df9c55a to 81b3f53 Compare August 12, 2026 12:00
@tomaszpatejko tomaszpatejko changed the title Draft: LLT-7558: blocking and unblocking doesnt'w work LLT-7558: Domain accessible after being removed from whitelist Aug 12, 2026
When whitelist changes, resolver's DNS cache should be flushed.
This way when domain is reblocked, the DNS query for its IP address
should not be handled from resolvers cache, but from tp-lite DNS server
and result in NXDOMAIN.
The test, at its initial step, whitelists a domain and checks query result of
the natlab tp-lite DNS server. The query response should contain a resolved IP address
of the domain that is cached in resolver cache.

Then the domain is removed for the whitelist. Subsequent query to the natlab tp-lite DNS
server should result in NXDOMAIN.
@tomaszpatejko
tomaszpatejko force-pushed the LLT-7558-blocking-unblocking-domain-doesnt-work branch from 8c5504f to c8ac042 Compare August 24, 2026 09:42
@matislovas

Copy link
Copy Markdown
Collaborator

You can squash c8ac042 commit with the 3ec2acf.

/// but a cached answer would be returned without the query ever reaching
/// the firewall.
pub fn flush_cache(&self) {
self.resolver.clear_cache();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this blocks until all requests in-flight are finished, and only than clears the cache?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand the code correctly, TrustDNS' resolver uses sync::Cache from moka-rs crate for its cache implementation, and the entire cache invalidation is delegated to that crate.

Moka-rs' sync::Cache::invalidate_all method does not remove any entries and just records current time as invalidation time for all the entries in the cache. Check the comment here: https://github.com/moka-rs/moka/blob/a616ec19e8d4ed938caf8b2c88090331d778d5da/src/sync/cache.rs#L1658

Actual removal of invalidated entries is delegated to Housekeeper that is triggered by get/insert methods. Housekeeper does not block reads but it blocks writes.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But as I see it, it still can cause problems with requests-in-flight. Before flushing the cache, we should check, if there are some and either:

  1. Wait for them to finish and put to cache.
  2. Cancel them, for them not to end in cache.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only situation, where we can avoid this problem with request-in-flight is that cache time entry (used to invalidate entries) is actually request_started and NOT request_put_to_cache

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I don't understand the issue you are trying to point out here. Could you elaborate a bit more?

) -> bool {
let domains_changed = {
let mut configured_state = self.configured_state.write();
let changed = configured_state.tp_lite_whitelisted_domains != domains;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we compare the redirects as well?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think redirects should be compared in this situation.

If I understand the comment for set_tp_lite_domain_whitelist, redirects contains pairs of DNS servers used for blocking or passing through a domain. So the change in this list does not drive the decision whether resolver cache should be flushed.

@matislovas matislovas Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My idea was to check both - the domains and redirects:

let changed_domains = configured_state.tp_lite_whitelisted_domains != domains;
let changed_redirects= configured_state.tp_lite_dns_redirects != redirects;
...
(changed_domains || changed_redirects)

redirects can influence DNAT usage, so my idea was to compare them as well.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can get rid of this discussion by flashing on every call to set_tp_lite_domain_whitelist. Realistically it's only called when: a) user added/or removed something from whitelist, b) user enabled or disabled tp. In both cases we want to flush the cache. So I don't think it's worth optimizing for some hard to imagine scenario.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants