all lists on 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal