Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions qubes/vm/mix/net.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,17 @@ def connected_vms(self):
@qubes.stateless_property
def dns(self):
'''DNS servers set up for this domain.'''
if self.netvm is not None or self.provides_network:
return StrSerializableTuple((
'10.139.1.1',
'10.139.1.2',
))
if self.netvm is not None:
Copy link
Member

Choose a reason for hiding this comment

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

It was self.netvm is not None or self.provides_network specifically to have virtual DNS addresses in sys-net too. Since you use self.netvm.features in a line below, you should check for self.features in case of no netvm. This asymmetric handling of sys-net is a bit weird, I agree, but since the addresses are constant anyway, it works just fine.

Copy link
Author

@1cho1ce 1cho1ce Oct 8, 2023

Choose a reason for hiding this comment

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

Is there a way to check if the qube has netvm or not from inside it?
This change was mainly so I could add reject rules to sys-net here based on whatever this qube's netvm DNS servers are set. Without it I couldn't find a way to check if qube is connected to a netvm to determine if it should pass or reject the "virtual" DNS queries.

Copy link
Author

@1cho1ce 1cho1ce Oct 8, 2023

Choose a reason for hiding this comment

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

Just to note the reason as to why did I check self.netvm.features.check_with_netvm is because I wanted to pass the qube usable primary and secondary virtual DNS servers.
For example, with ipv6 feature enabled only in sys-vpn and all qubes connected to it, if I just check if sys-vpn has ipv6 feature and give it IPv6 primary and IPv4 secondary virtual DNS servers then it won't be able to use the primary IPv6 server because the sys-vpn's netvm doesn't support IPv6 so it's better to give sys-vpn two IPv4 virtual DNS from netvm that are supported by the qube's netvm.

Copy link
Author

Choose a reason for hiding this comment

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

Is there a way to check if the qube has netvm or not from inside it?

I guess I should just check if /qubes-ip is set.

Copy link
Member

Choose a reason for hiding this comment

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

For example, with ipv6 feature enabled only in sys-vpn and all qubes connected to it, if I just check if sys-vpn has ipv6 feature and give it IPv6 primary and IPv4 secondary virtual DNS servers then it won't be able to use the primary IPv6 server because the sys-vpn's netvm doesn't support IPv6 so it's better to give sys-vpn two IPv4 virtual DNS from netvm that are supported by the qube's netvm.

That very much depends what your VPN does. If it tunnels all the traffic (IPv4 + IPv6) inside a IPv4 tunnel, then IPv6 DNS should also work. And in that case, the VPN software will set DNS in sys-vpn (in /etc/resolv.conf, or systemd-resolved) to something else than virtual DNS, so all should be fine.

We have two sets of DNS addresses in the qubesdb:

  1. /qubes-primary-dns, /qubes-secondary-dns - this is what qube itself should use (and when providing network to others - where should redirect DNS traffic to)
  2. /qubes-netvm-primary-dns, /qubes-netvm-secondary-dns - this is what addresses should be intercepted and redirected to the actual DNS (which may be the virtual one in connected netvm)

The first set in a qube should match the second set in the qube's netvm. I wouldn't be surprised if it's mixed up right now (because we had just one possibility there).

So, lets suppose setup like this: sys-net (no ipv6) -> sys-vpn (ipv6) -> some-vm (ipv6 too, because connected to sys-vpn)

  • sys-net should have both sets IPv4-only
  • sys-vpn should have first set IPv4-only, but second IPv6+IPv4
  • some-vm should have the first set IPv6+IPv4 (and no second set because it doesn't provide network to others)

In sys-vpn, if it doesn't tunnel IPv6 DNS into VPN (to some real DNS server), it should have a reject rule on IPv6 virtual DNS address, because sys-net doesn't support it. This can be done by having virtual IPv6 DNS reject rule in postrouting instead of prerouting - then if VPN redirects the IPv6 DNS to somewhere else, it will bypass the reject rule and will work; otherwise it will get rejected (and hopefully the ICMP response will be forwarded back to the client - requires testing).

Is there a way to check if the qube has netvm or not from inside it?

I guess I should just check if /qubes-ip is set.

Yes, that works.

Copy link
Author

Choose a reason for hiding this comment

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

In sys-vpn, if it doesn't tunnel IPv6 DNS into VPN (to some real DNS server), it should have a reject rule on IPv6 virtual DNS address, because sys-net doesn't support it. This can be done by having virtual IPv6 DNS reject rule in postrouting instead of prerouting - then if VPN redirects the IPv6 DNS to somewhere else, it will bypass the reject rule and will work; otherwise it will get rejected (and hopefully the ICMP response will be forwarded back to the client - requires testing).

I've decided to add jump from dnat-dns to separate chain custom-dnat-dns for VPN rules instead of adding reject rules in postrouting or forward chains for the sake of uniformity in the same way as chain input has chain custom-input and chain forward has chain custom-forward.
VPN should add its DNS redirects to custom-dnat-dns chain.

I think the PR is ready for a review now.

if self.netvm.features.check_with_netvm('ipv6', False):
return StrSerializableTuple((
'fd09:24ef:4179::a8b:1',
'10.139.1.1',
))
else:
return StrSerializableTuple((
'10.139.1.1',
'10.139.1.2',
))

return None

Expand Down
5 changes: 3 additions & 2 deletions qubes/vm/qubesvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -2251,8 +2251,9 @@ def create_qdb_entries(self):
str(self.gateway6))
self.untrusted_qdb.write('/qubes-netvm-netmask', str(self.netmask))

for i, addr in zip(('primary', 'secondary'), self.dns):
self.untrusted_qdb.write('/qubes-netvm-{}-dns'.format(i), addr)
if self.netvm is not None:
Copy link
Member

Choose a reason for hiding this comment

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

This change made you hardcode virtual DNS addresses in the other PR. If you drop this condition, you will always have them available.

for i, addr in zip(('primary', 'secondary'), self.dns):
self.untrusted_qdb.write('/qubes-netvm-{}-dns'.format(i), addr)

if self.netvm is not None:
self.untrusted_qdb.write('/qubes-mac', str(self.mac))
Expand Down