Summary
When Linux.Remediation.Quarantine is applied on a client whose server_urls are configured with a domain name (rather than a direct IP), the server address is not resolved in time. The nftables table and rules are still installed, but instead of allowing the Velociraptor frontend the policy ends up blocking it, so the client loses contact with the server. The built-in connectivity self-test then fails and the whole table is rolled back.
The problem does not occur when server_urls are configured with literal IP addresses.
Expected behaviour
The frontend is resolved and an allow-rule for the server address is installed, so the client stays connected while all other traffic is blocked.
Steps to reproduce
- Configure the client
server_urls with a domain name, e.g.
https://<your-domain>:8000/.
- Apply
Linux.Remediation.Quarantine to the host.
Actual behaviour
The nftables rules are added, but the Velociraptor server is blocked rather than allowed, and the client loses its connection. The following lookup error is observed:
host: Lookup error : lookup <client-id>.<your-domain> on <dns-ip>:53: read udp <client-ip>:54802-><dns-ip>:53: i/o timeout
The DNS lookup times out, which suggests that resolution is attempted after the drop policy has already been installed (so DNS is already blocked by the time the frontend rule is built).
Likely cause
I'm not certain, but it looks like the server hostname is only resolved once the quarantine rules are already being applied i.e. after DNS has been blocked so the lookup times out and no valid allow-rule for the server is created.
LET add_to_out_chain(DstAddr, DstPort) = (..., 'ip', 'daddr', host(name=DstAddr)[0], ...)
LET extracted_config <= SELECT get_domain(URL=_value) AS DstAddr, ...
Workaround (to assess)
A custom version was created in which the frontend server is resolved first (up front, before any drop rule is applied). With that change the server stays reachable and the remaining traffic is blocked as intended.
extracted_config resolve up front and discard rows that don't resolve:
// extract Velociraptor config for policy
-LET extracted_config <= SELECT get_domain(URL=_value) AS DstAddr,
+LET extracted_config <= SELECT host(name=get_domain(URL=_value))[0] AS DstAddr,
get_port(URL=_value) AS DstPort,
'VelociraptorFrontEnd' AS Description,
_value AS URL
FROM foreach(row=config.server_urls)
+WHERE DstAddr
add_to_in_chain use the resolved IP directly:
LET add_to_in_chain(DstAddr, DstPort) = (pathToNFT, 'add', 'rule', 'inet',
- TableName, 'inbound_chain', 'ip', 'saddr', host(name=DstAddr)[0],
+ TableName, 'inbound_chain', 'ip', 'saddr', DstAddr,
'tcp', 'sport', '{', DstPort, '}', 'ct', 'state', 'established', 'accept')
add_to_out_chain same change on the outbound side:
LET add_to_out_chain(DstAddr, DstPort) = (pathToNFT, 'add', 'rule', 'inet',
- TableName, 'outbound_chain', 'ip', 'daddr', host(name=DstAddr)[0],
+ TableName, 'outbound_chain', 'ip', 'daddr', DstAddr,
'tcp', 'dport', '{', DstPort, '}', 'ct', 'state', 'established,new', 'accept')
Summary
When
Linux.Remediation.Quarantineis applied on a client whoseserver_urlsare configured with a domain name (rather than a direct IP), the server address is not resolved in time. Thenftablestable and rules are still installed, but instead of allowing the Velociraptor frontend the policy ends up blocking it, so the client loses contact with the server. The built-in connectivity self-test then fails and the whole table is rolled back.The problem does not occur when
server_urlsare configured with literal IP addresses.Expected behaviour
The frontend is resolved and an allow-rule for the server address is installed, so the client stays connected while all other traffic is blocked.
Steps to reproduce
server_urlswith a domain name, e.g.https://<your-domain>:8000/.Linux.Remediation.Quarantineto the host.Actual behaviour
The
nftablesrules are added, but the Velociraptor server is blocked rather than allowed, and the client loses its connection. The following lookup error is observed:The DNS lookup times out, which suggests that resolution is attempted after the drop policy has already been installed (so DNS is already blocked by the time the frontend rule is built).
Likely cause
I'm not certain, but it looks like the server hostname is only resolved once the quarantine rules are already being applied i.e. after DNS has been blocked so the lookup times out and no valid allow-rule for the server is created.
Workaround (to assess)
A custom version was created in which the frontend server is resolved first (up front, before any drop rule is applied). With that change the server stays reachable and the remaining traffic is blocked as intended.
extracted_configresolve up front and discard rows that don't resolve:add_to_in_chainuse the resolved IP directly:add_to_out_chainsame change on the outbound side: