From dc0056f6e88582c0b8725e108fd86e52fc88ba08 Mon Sep 17 00:00:00 2001 From: Mathias Lang Date: Sun, 24 Mar 2024 16:01:00 +0100 Subject: [PATCH] networking: Workaround 2693 by ignoring resolv.conf entries starting with dot Currently, systems without a FQDN can be mishandled by facter for certain `/etc/resolv.conf` content. This was initially noticed when systemd-resolved was installed on a host without domain. systemd-resolved stub resolver sets 'search .' as a search domain, which results in the following hostname/domain/fqdn triplet: foo, ., foo... See: https://github.com/systemd/systemd/blob/v255/src/resolve/resolv.conf#L19 This is wrong on multiple levels: first, facter does not seem to handle '.' (the root level) well, and there have been PRs to remove the trailing dot in FQDN as far back as 2012 (PR 200), leaving user with a convenient, but sometimes ambiguous string that is not fully qualified. This commit implements a a middle ground solution to support top-level/domainless servers without making a breaking change. Additionally, it adds more coverage for various search cases. --- lib/facter/resolvers/hostname.rb | 4 ++-- lib/facter/resolvers/linux/hostname.rb | 4 ++-- spec/facter/resolvers/linux/hostname_spec.rb | 24 ++++++++++++++++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/lib/facter/resolvers/hostname.rb b/lib/facter/resolvers/hostname.rb index eba8782db1..53c7f9ac3c 100644 --- a/lib/facter/resolvers/hostname.rb +++ b/lib/facter/resolvers/hostname.rb @@ -68,9 +68,9 @@ def hostname_and_no_domain?(hostname, domain) def read_domain file_content = Facter::Util::FileHelper.safe_read('/etc/resolv.conf') - if file_content =~ /^domain\s+(\S+)/ + if file_content =~ /^domain\s+([^.]\S+)/ Regexp.last_match(1) - elsif file_content =~ /^search\s+(\S+)/ + elsif file_content =~ /^search\s+([^.]\S+)/ Regexp.last_match(1) end end diff --git a/lib/facter/resolvers/linux/hostname.rb b/lib/facter/resolvers/linux/hostname.rb index e2dba54eb6..32e0688559 100644 --- a/lib/facter/resolvers/linux/hostname.rb +++ b/lib/facter/resolvers/linux/hostname.rb @@ -96,9 +96,9 @@ def hostname_and_no_domain?(hostname, domain) def read_domain file_content = Facter::Util::FileHelper.safe_read('/etc/resolv.conf') - if file_content =~ /^domain\s+(\S+)/ + if file_content =~ /^domain\s+([^.]\S+)/ Regexp.last_match(1) - elsif file_content =~ /^search\s+(\S+)/ + elsif file_content =~ /^search\s+([^.]\S+)/ Regexp.last_match(1) end end diff --git a/spec/facter/resolvers/linux/hostname_spec.rb b/spec/facter/resolvers/linux/hostname_spec.rb index a69bdebf8e..f3ee0e77fc 100644 --- a/spec/facter/resolvers/linux/hostname_spec.rb +++ b/spec/facter/resolvers/linux/hostname_spec.rb @@ -79,6 +79,30 @@ it_behaves_like 'detects values' end + + context 'when /etc/resolv.conf has "search ."' do + let(:resolv_conf) { "search .\n" } + let(:domain) { nil } + let(:fqdn) { hostname } + + it_behaves_like 'detects values' + end + + context 'when /etc/resolv.conf has "search ." with multiple entires' do + let(:resolv_conf) { 'search . foo.bar' } + let(:domain) { nil } + let(:fqdn) { hostname } + + it_behaves_like 'detects values' + end + + context 'when /etc/resolv.conf has "search" with multiple entires' do + let(:resolv_conf) { 'search foo.bar example.com' } + let(:domain) { 'foo.bar' } + let(:fqdn) { "#{hostname}.#{domain}" } + + it_behaves_like 'detects values' + end end context 'when FFI is not installed' do