From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 0E9731FF13B for ; Wed, 11 Mar 2026 12:21:52 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 0E0F917B8C; Wed, 11 Mar 2026 12:21:46 +0100 (CET) From: Filip Schauer 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 Message-ID: <20260311112057.48653-1-f.schauer@proxmox.com> X-Mailer: git-send-email 2.47.3 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1773228036683 X-SPAM-LEVEL: Spam detection results: 0 AWL -1.056 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment RCVD_IN_VALIDITY_CERTIFIED_BLOCKED 0.408 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_RPBL_BLOCKED 0.819 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_SAFE_BLOCKED 0.903 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: 7Y3HLQZS4UINSEASOAM6GD2DXSSG7IGE X-Message-ID-Hash: 7Y3HLQZS4UINSEASOAM6GD2DXSSG7IGE X-MailFrom: f.schauer@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: 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 --- 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