dns-delegates: add support for setting a firewall mark

This makes it possible to have DNS requests for certain domains routed
differently than normal requests, which is for instance useful when
using policy routing to route traffic over a VPN but DNS requests for
the VPN endpoint itself, should be routed differently.

It doesn't make much sense to configure a firewall mark at the level of
a network interface, but at the level of a DNS delegate it can be very
useful.
This commit is contained in:
r-vdp
2026-02-16 11:09:48 +01:00
committed by Lennart Poettering
parent a5ceab95ab
commit e271497d97
5 changed files with 25 additions and 2 deletions
+15 -2
View File
@@ -69,6 +69,18 @@
<xi:include href="version-info.xml" xpointer="v258"/>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>FirewallMark=</varname></term>
<listitem>
<para>Takes a 32 bit unsigned integer value. Controls the firewall mark of packets generated by the
socket used to make DNS requests for this DNS delegate. This can be used in the firewall logic to
filter packets from this socket.
This sets the <constant>SO_MARK</constant> socket option. See <citerefentry
project='die-net'><refentrytitle>iptables</refentrytitle><manvolnum>8</manvolnum></citerefentry> for
details.</para>
<xi:include href="version-info.xml" xpointer="v260"/>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
@@ -79,10 +91,11 @@
<programlisting># /etc/systemd/dns-delegate.d/foobar.dns-delegate
[Delegate]
DNS=203.0.113.47
Domains=foobar.com</programlisting>
Domains=foobar.com
FirewallMark=42</programlisting>
<para>This ensures lookups of <literal>foobar.com</literal> and any domains below it are directed to
DNS server 203.0.113.47.</para>
DNS server 203.0.113.47 and any packets related to this lookup have a firewall mark set to 42.</para>
</example>
</refsect1>
@@ -21,3 +21,4 @@ struct ConfigPerfItem;
Delegate.DNS, config_parse_delegate_dns_servers, 0, 0
Delegate.Domains, config_parse_delegate_domains, 0, 0
Delegate.DefaultRoute, config_parse_tristate, 0, offsetof(DnsDelegate, default_route)
Delegate.FirewallMark, config_parse_unsigned, 0, offsetof(DnsDelegate, fwmark)
+2
View File
@@ -23,6 +23,8 @@ typedef struct DnsDelegate {
int default_route;
uint32_t fwmark;
DnsScope *scope;
LIST_FIELDS(DnsDelegate, delegates);
+6
View File
@@ -475,6 +475,12 @@ static int dns_scope_socket(
return r;
}
if (s->delegate && s->delegate->fwmark > 0) {
r = setsockopt_int(fd, SOL_SOCKET, SO_MARK, s->delegate->fwmark);
if (r < 0)
return log_debug_errno(r, "Failed to set firewall mark on DNS socket: %m)");
}
bool addr_is_nonlocal = s->link &&
!manager_find_link_address(s->manager, sa.sa.sa_family, sockaddr_in_addr(&sa.sa)) &&
in_addr_is_localhost(sa.sa.sa_family, sockaddr_in_addr(&sa.sa)) == 0;
+1
View File
@@ -1452,6 +1452,7 @@ testcase_delegate() {
[Delegate]
DNS=192.168.77.78
Domains=exercise.test
FirewallMark=42
EOF
systemctl reload systemd-resolved
resolvectl status