Skip to content

Commit e08a478

Browse files
olethanhAntonyjin
authored andcommitted
Feature: allow IPv6 DNS (#455)
* Feature: allow IPv6 DNS Problem IPv6 DNS were automatically filtered when detected from resolvectl Solution: Nameservers are now split into ipv4 and ipv6 and can be passed to the VM accordingly At the moment we pass them if the ipv6 parameter is present on the tap interface but we need a more robust detection method * Display proper env conf
1 parent e98c2a8 commit e08a478

File tree

3 files changed

+28
-23
lines changed

3 files changed

+28
-23
lines changed

src/aleph/vm/conf.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -76,17 +76,6 @@ def resolvectl_dns_servers(interface: str) -> Iterable[str]:
7676
yield server.strip()
7777

7878

79-
def resolvectl_dns_servers_ipv4(interface: str) -> Iterable[str]:
80-
"""
81-
Use resolvectl to list available IPv4 DNS servers.
82-
VMs only support IPv4 networking for now, we must exclude IPv6 DNS from their config.
83-
"""
84-
for server in resolvectl_dns_servers(interface):
85-
ip_addr = ipaddress.ip_address(server)
86-
if isinstance(ip_addr, ipaddress.IPv4Address):
87-
yield server
88-
89-
9079
def get_default_interface() -> str | None:
9180
"""Returns the default network interface"""
9281
with open("/proc/net/route") as f:
@@ -104,7 +93,7 @@ def obtain_dns_ips(dns_resolver: DnsResolver, network_interface: str) -> list[st
10493
# Use a try-except approach since resolvectl can be present but disabled and raise the following
10594
# "Failed to get global data: Unit dbus-org.freedesktop.resolve1.service not found."
10695
try:
107-
return list(resolvectl_dns_servers_ipv4(interface=network_interface))
96+
return list(resolvectl_dns_servers(interface=network_interface))
10897
except (FileNotFoundError, CalledProcessError) as error:
10998
if Path("/etc/resolv.conf").exists():
11099
return list(etc_resolv_conf_dns_servers())
@@ -116,7 +105,7 @@ def obtain_dns_ips(dns_resolver: DnsResolver, network_interface: str) -> list[st
116105
return list(etc_resolv_conf_dns_servers())
117106

118107
elif dns_resolver == DnsResolver.resolvectl:
119-
return list(resolvectl_dns_servers_ipv4(interface=network_interface))
108+
return list(resolvectl_dns_servers(interface=network_interface))
120109

121110
else:
122111
msg = "No DNS resolve defined, this should never happen."
@@ -182,8 +171,13 @@ class Settings(BaseSettings):
182171
description="Use the Neighbor Discovery Protocol Proxy to respond to Router Solicitation for instances on IPv6",
183172
)
184173

185-
DNS_RESOLUTION: DnsResolver | None = DnsResolver.detect
174+
DNS_RESOLUTION: DnsResolver | None = Field(
175+
default=DnsResolver.detect,
176+
description="Method used to resolve the dns server if DNS_NAMESERVERS is not present.",
177+
)
186178
DNS_NAMESERVERS: list[str] | None = None
179+
DNS_NAMESERVERS_IPV4: list[str] | None
180+
DNS_NAMESERVERS_IPV6: list[str] | None
187181

188182
FIRECRACKER_PATH: Path = Path("/opt/firecracker/firecracker")
189183
JAILER_PATH: Path = Path("/opt/firecracker/jailer")
@@ -445,6 +439,18 @@ def setup(self):
445439
network_interface=self.NETWORK_INTERFACE,
446440
)
447441

442+
if not self.DNS_NAMESERVERS_IPV4:
443+
self.DNS_NAMESERVERS_IPV4 = []
444+
if not self.DNS_NAMESERVERS_IPV6:
445+
self.DNS_NAMESERVERS_IPV6 = []
446+
if self.DNS_NAMESERVERS:
447+
for server in self.DNS_NAMESERVERS:
448+
ip_addr = ipaddress.ip_address(server)
449+
if isinstance(ip_addr, ipaddress.IPv4Address):
450+
self.DNS_NAMESERVERS_IPV4.append(server)
451+
if isinstance(ip_addr, ipaddress.IPv6Address):
452+
self.DNS_NAMESERVERS_IPV6.append(server)
453+
448454
if not settings.ENABLE_QEMU_SUPPORT:
449455
# If QEmu is not supported, ignore the setting and use Firecracker by default
450456
settings.INSTANCE_DEFAULT_HYPERVISOR = HypervisorType.firecracker
@@ -462,7 +468,7 @@ def display(self) -> str:
462468
else:
463469
attributes[attr] = getattr(self, attr)
464470

465-
return "\n".join(f"{attribute:<27} = {value}" for attribute, value in attributes.items())
471+
return "\n".join(f"{self.Config.env_prefix}{attribute} = {value}" for attribute, value in attributes.items())
466472

467473
def __init__(
468474
self,

src/aleph/vm/controllers/firecracker/instance.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,11 @@ def _create_network_file(self) -> bytes:
198198
ipv6 = self.get_ipv6()
199199
ipv6_gateway = self.get_ipv6_gateway()
200200

201+
nameservers_ip = []
202+
if ip:
203+
nameservers_ip = settings.DNS_NAMESERVERS_IPV4
204+
if ipv6:
205+
nameservers_ip += settings.DNS_NAMESERVERS_IPV6
201206
network = {
202207
"ethernets": {
203208
"eth0": {
@@ -207,7 +212,7 @@ def _create_network_file(self) -> bytes:
207212
"gateway4": route,
208213
"gateway6": ipv6_gateway,
209214
"nameservers": {
210-
"addresses": settings.DNS_NAMESERVERS,
215+
"addresses": nameservers_ip,
211216
},
212217
},
213218
},

tests/supervisor/test_resolvectl_dns_servers.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import os
33
from unittest import mock
44

5-
from aleph.vm.conf import resolvectl_dns_servers, resolvectl_dns_servers_ipv4
5+
from aleph.vm.conf import resolvectl_dns_servers
66

77
os.environ["ALEPH_VM_ALLOW_VM_NETWORKING"] = "False"
88

@@ -17,9 +17,6 @@ def test_resolvectl():
1717
dns_servers = set(resolvectl_dns_servers("eth0"))
1818
assert dns_servers == servers
1919

20-
dns_servers_ipv4 = set(resolvectl_dns_servers_ipv4("eth0"))
21-
assert dns_servers_ipv4 == servers
22-
2320

2421
def test_resolvectl_ipv6():
2522
with mock.patch(
@@ -31,6 +28,3 @@ def test_resolvectl_ipv6():
3128

3229
dns_servers = set(resolvectl_dns_servers("eth0"))
3330
assert dns_servers == ipv4_servers | ipv6_servers
34-
35-
dns_servers_ipv4 = set(resolvectl_dns_servers_ipv4("eth0"))
36-
assert dns_servers_ipv4 == ipv4_servers

0 commit comments

Comments
 (0)