public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [PATCH container] fix #7388: prefer container DNS config over host-managed DHCP
@ 2026-03-11 11:20 Filip Schauer
  0 siblings, 0 replies; only message in thread
From: Filip Schauer @ 2026-03-11 11:20 UTC (permalink / raw)
  To: pve-devel

For host-managed container network interfaces using DHCP, dhclient may
overwrite /etc/resolv.conf with DNS information supplied by the DHCP
server, causing any explicitly configured nameserver/searchdomain to be
silently ignored.

Fix this with a custom dhclient.conf that ensures the container config
takes precedence over any DNS settings offered by the DHCP server.

Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
---
 src/PVE/LXC.pm | 46 +++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 39 insertions(+), 7 deletions(-)

diff --git a/src/PVE/LXC.pm b/src/PVE/LXC.pm
index 9633451..c4d4a11 100644
--- a/src/PVE/LXC.pm
+++ b/src/PVE/LXC.pm
@@ -5,7 +5,7 @@ use warnings;
 
 use Cwd qw();
 use Errno qw(ELOOP ENOTDIR EROFS ECONNREFUSED EEXIST);
-use Fcntl qw(O_RDONLY O_WRONLY O_NOFOLLOW O_DIRECTORY O_CREAT :mode);
+use Fcntl qw(O_RDONLY O_WRONLY O_NOFOLLOW O_DIRECTORY O_CREAT SEEK_SET :mode);
 use File::Basename;
 use File::Path;
 use File::Spec;
@@ -1324,12 +1324,42 @@ sub get_interfaces {
 }
 
 sub manage_dhclient {
-    my ($action, $vmid, $ipversion, $eth, $rootdir) = @_;
+    my ($action, $vmid, $conf, $ipversion, $eth, $rootdir) = @_;
 
     File::Path::make_path("/var/lib/lxc/$vmid/hook") if $action eq 'start';
     my $pidfile = "/var/lib/lxc/$vmid/hook/dhclient$ipversion-$eth.pid";
     my $leasefile = "/var/lib/lxc/$vmid/hook/dhclient$ipversion-$eth.leases";
     my $scriptfile = '/usr/share/lxc/hooks/dhclient-script';
+
+    # Copied from /etc/dhcp/dhclient.conf in isc-dhcp-client Debian package
+    my $config =
+        "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n"
+        . "send host-name = gethostname();\n"
+        . "request subnet-mask, broadcast-address, time-offset, routers, "
+        . "domain-name, domain-name-servers, domain-search, host-name, "
+        . "dhcp6.name-servers, dhcp6.domain-search, dhcp6.fqdn, dhcp6.sntp-servers, "
+        . "netbios-name-servers, netbios-scope, interface-mtu, "
+        . "rfc3442-classless-static-routes, ntp-servers;\n";
+
+    if ($ipversion == 6) {
+        if (my @nameservers = grep { /$IPV6RE/ } PVE::Tools::split_list($conf->{nameserver})) {
+            $config .= "supersede dhcp6.name-servers " . join(", ", @nameservers) . ";\n";
+        }
+    } elsif (my @nameservers = grep { /$IPV4RE/ } PVE::Tools::split_list($conf->{nameserver})) {
+        $config .= "supersede domain-name-servers " . join(", ", @nameservers) . ";\n";
+    }
+
+    if (my @searchdomains = PVE::Tools::split_list($conf->{searchdomain})) {
+        $config .= "supersede " . (($ipversion == 6) ? "dhcp6." : "") . "domain-search ";
+        $config .= join(", ", map { "\"$_\"" } @searchdomains) . ";\n";
+    }
+
+    open(my $configfh, '+>', undef) or die "failed to create dhclient config: $!";
+    print $configfh $config;
+    $configfh->flush();
+    sysseek($configfh, 0, SEEK_SET);
+    my $configfile = "/proc/$$/fd/" . fileno($configfh);
+
     PVE::Tools::run_command([
         'lxc-attach',
         '-n',
@@ -1351,6 +1381,8 @@ sub manage_dhclient {
         "ROOTFS=$rootdir",
         '-sf',
         $scriptfile,
+        '-cf',
+        $configfile,
         $eth,
     ]);
 }
@@ -1411,10 +1443,10 @@ sub update_ipconfig {
         my $is_real_ip = ($newip && $newip !~ /^(?:auto|dhcp|manual)$/);
         if ($change_ip) {
             if ($newnet->{'host-managed'} && $newip && $newip eq 'dhcp') {
-                manage_dhclient('start', $vmid, $ipversion, $eth, $rootdir);
+                manage_dhclient('start', $vmid, $conf, $ipversion, $eth, $rootdir);
             }
             if ($optdata->{'host-managed'} && $oldip && $oldip eq 'dhcp') {
-                manage_dhclient('stop', $vmid, $ipversion, $eth, $rootdir);
+                manage_dhclient('stop', $vmid, $conf, $ipversion, $eth, $rootdir);
             }
 
             if ($is_real_ip) {
@@ -1425,7 +1457,7 @@ sub update_ipconfig {
                 }
             }
         } elsif ($optdata->{'host-managed'} && !$newnet->{'host-managed'}) {
-            manage_dhclient('stop', $vmid, $ipversion, $eth, $rootdir);
+            manage_dhclient('stop', $vmid, $conf, $ipversion, $eth, $rootdir);
         }
 
         # step 2: replace gateway
@@ -3227,12 +3259,12 @@ sub vm_start {
     my $rootdir = "/proc/$pid/root";
 
     for my $eth (@managed_dhcpv4_interfaces) {
-        eval { manage_dhclient('start', $vmid, 4, $eth, $rootdir) };
+        eval { manage_dhclient('start', $vmid, $conf, 4, $eth, $rootdir) };
         PVE::RESTEnvironment::log_warn("DHCP failed - $@") if $@;
     }
 
     for my $eth (@managed_dhcpv6_interfaces) {
-        eval { manage_dhclient('start', $vmid, 6, $eth, $rootdir) };
+        eval { manage_dhclient('start', $vmid, $conf, 6, $eth, $rootdir) };
         PVE::RESTEnvironment::log_warn("DHCP failed - $@") if $@;
     }
 
-- 
2.47.3





^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-03-11 11:21 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-03-11 11:20 [PATCH container] fix #7388: prefer container DNS config over host-managed DHCP Filip Schauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal