public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Filip Schauer <f.schauer@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH container] fix #7388: prefer container DNS config over host-managed DHCP
Date: Wed, 11 Mar 2026 12:20:44 +0100	[thread overview]
Message-ID: <20260311112057.48653-1-f.schauer@proxmox.com> (raw)

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





                 reply	other threads:[~2026-03-11 11:21 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260311112057.48653-1-f.schauer@proxmox.com \
    --to=f.schauer@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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