mirror of
https://github.com/linux-system-roles/network.git
synced 2026-01-23 02:15:17 +00:00
Fix: support dns_search and dns_options for all address family
`dns_search` and `dns_options` should not be specific to the address family. Previously, `dns_search` and `dns_options` were only supported for IPv4 nameservers, so we also need to support `dns_search` and `dns_options` for IPv6 nameservers. Signed-off-by: Wen Liang <liangwen12year@gmail.com>
This commit is contained in:
parent
2444e27cce
commit
93e509b533
5 changed files with 165 additions and 17 deletions
16
README.md
16
README.md
|
|
@ -364,21 +364,25 @@ The IP configuration supports the following options:
|
|||
|
||||
- `dns_search`
|
||||
|
||||
`dns_search` is only supported for IPv4 nameservers. Manual DNS configuration can
|
||||
be specified via a list of domains to search given in the `dns_search` option.
|
||||
Manual DNS configuration can be specified via a list of domains to search given in
|
||||
the `dns_search` option.
|
||||
|
||||
- `dns_options`
|
||||
|
||||
`dns_options` is only supported for the NetworkManager provider and IPv4
|
||||
nameservers. Manual DNS configuration via a list of DNS options can be given in the
|
||||
`dns_options`. The list of supported DNS options for IPv4 nameservers is described
|
||||
in [man 5 resolv.conf](https://man7.org/linux/man-pages/man5/resolv.conf.5.html).
|
||||
`dns_options` is only supported for the NetworkManager provider. Manual DNS
|
||||
configuration via a list of DNS options can be given in the `dns_options`. The list
|
||||
of supported DNS options for IPv4 nameservers is described in
|
||||
[man 5 resolv.conf](https://man7.org/linux/man-pages/man5/resolv.conf.5.html).
|
||||
Currently, the list of supported DNS options is:
|
||||
- `attempts:n`
|
||||
- `debug`
|
||||
- `edns0`
|
||||
- `inet6`
|
||||
- `ip6-bytestring`
|
||||
- `ip6-dotint`
|
||||
- `ndots:n`
|
||||
- `no-check-names`
|
||||
- `no-ip6-dotint`
|
||||
- `no-reload`
|
||||
- `no-tld-query`
|
||||
- `rotate`
|
||||
|
|
|
|||
|
|
@ -1023,14 +1023,14 @@ class NMUtil:
|
|||
s_ip4.set_property(
|
||||
NM.SETTING_IP_CONFIG_ROUTE_METRIC, ip["route_metric4"]
|
||||
)
|
||||
for d in ip["dns"]:
|
||||
if d["family"] == socket.AF_INET:
|
||||
s_ip4.add_dns(d["address"])
|
||||
for s in ip["dns_search"]:
|
||||
s_ip4.add_dns_search(s)
|
||||
for nameserver in ip["dns"]:
|
||||
if nameserver["family"] == socket.AF_INET:
|
||||
s_ip4.add_dns(nameserver["address"])
|
||||
for search_domain in ip["dns_search"]:
|
||||
s_ip4.add_dns_search(search_domain)
|
||||
s_ip4.clear_dns_options(True)
|
||||
for s in ip["dns_options"]:
|
||||
s_ip4.add_dns_option(s)
|
||||
for option in ip["dns_options"]:
|
||||
s_ip4.add_dns_option(option)
|
||||
|
||||
if ip["ipv6_disabled"]:
|
||||
s_ip6.set_property(NM.SETTING_IP_CONFIG_METHOD, "disabled")
|
||||
|
|
@ -1056,9 +1056,14 @@ class NMUtil:
|
|||
s_ip6.set_property(
|
||||
NM.SETTING_IP_CONFIG_ROUTE_METRIC, ip["route_metric6"]
|
||||
)
|
||||
for d in ip["dns"]:
|
||||
if d["family"] == socket.AF_INET6:
|
||||
s_ip6.add_dns(d["address"])
|
||||
for nameserver in ip["dns"]:
|
||||
if nameserver["family"] == socket.AF_INET6:
|
||||
s_ip6.add_dns(nameserver["address"])
|
||||
for search_domain in ip["dns_search"]:
|
||||
s_ip6.add_dns_search(search_domain)
|
||||
s_ip6.clear_dns_options(True)
|
||||
for option in ip["dns_options"]:
|
||||
s_ip6.add_dns_option(option)
|
||||
|
||||
if ip["route_append_only"] and connection_current:
|
||||
for r in self.setting_ip_config_get_routes(
|
||||
|
|
|
|||
|
|
@ -534,8 +534,12 @@ class ArgValidator_DictIP(ArgValidatorDict):
|
|||
r"^attempts:([1-9]\d*|0)$",
|
||||
r"^debug$",
|
||||
r"^edns0$",
|
||||
r"^inet6$",
|
||||
r"^ip6-bytestring$",
|
||||
r"^ip6-dotint$",
|
||||
r"^ndots:([1-9]\d*|0)$",
|
||||
r"^no-check-names$",
|
||||
r"^no-ip6-dotint$",
|
||||
r"^no-reload$",
|
||||
r"^no-tld-query$",
|
||||
r"^rotate$",
|
||||
|
|
@ -1759,6 +1763,13 @@ class ArgValidator_ListConnections(ArgValidatorList):
|
|||
VALIDATE_ONE_MODE_INITSCRIPTS = "initscripts"
|
||||
|
||||
def validate_connection_one(self, mode, connections, idx):
|
||||
def _ipv4_enabled(connection):
|
||||
has_addrs4 = any(
|
||||
address["family"] == socket.AF_INET
|
||||
for address in connection["ip"]["address"]
|
||||
)
|
||||
return connection["ip"]["dhcp4"] or has_addrs4
|
||||
|
||||
connection = connections[idx]
|
||||
if "type" not in connection:
|
||||
return
|
||||
|
|
@ -1832,3 +1843,45 @@ class ArgValidator_ListConnections(ArgValidatorList):
|
|||
idx,
|
||||
"ip.ipv6_disabled is not supported by initscripts.",
|
||||
)
|
||||
# Setting ip.dns is not allowed when corresponding IP method for that
|
||||
# nameserver is disabled
|
||||
for nameserver in connection["ip"]["dns"]:
|
||||
if nameserver["family"] == socket.AF_INET and not _ipv4_enabled(connection):
|
||||
raise ValidationError.from_connection(
|
||||
idx,
|
||||
"IPv4 needs to be enabled to support IPv4 nameservers.",
|
||||
)
|
||||
if (
|
||||
nameserver["family"] == socket.AF_INET6
|
||||
and connection["ip"]["ipv6_disabled"]
|
||||
):
|
||||
raise ValidationError.from_connection(
|
||||
idx,
|
||||
"IPv6 needs to be enabled to support IPv6 nameservers.",
|
||||
)
|
||||
# when IPv4 and IPv6 are disabled, setting ip.dns_options or
|
||||
# ip.dns_search is not allowed
|
||||
if connection["ip"]["dns_search"] or connection["ip"]["dns_options"]:
|
||||
if not _ipv4_enabled(connection) and connection["ip"]["ipv6_disabled"]:
|
||||
raise ValidationError.from_connection(
|
||||
idx,
|
||||
"Setting 'dns_search' or 'dns_options' is not allowed when "
|
||||
"both IPv4 and IPv6 are disabled.",
|
||||
)
|
||||
# DNS options 'inet6', 'ip6-bytestring', 'ip6-dotint', 'no-ip6-dotint' are only
|
||||
# supported for IPv6 configuration, so raise errors when IPv6 is disabled
|
||||
if any(
|
||||
option in connection["ip"]["dns_options"]
|
||||
for option in [
|
||||
"inet6",
|
||||
"ip6-bytestring",
|
||||
"ip6-dotint",
|
||||
"no-ip6-dotint",
|
||||
]
|
||||
):
|
||||
if connection["ip"]["ipv6_disabled"]:
|
||||
raise ValidationError.from_connection(
|
||||
idx,
|
||||
"Setting DNS options 'inet6', 'ip6-bytestring', 'ip6-dotint', "
|
||||
"'no-ip6-dotint' is not allowed when IPv6 is disabled.",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
dns:
|
||||
- 192.0.2.2
|
||||
- 198.51.100.5
|
||||
- 2001:db8::20
|
||||
dns_search:
|
||||
- example.com
|
||||
- example.org
|
||||
|
|
@ -64,7 +65,7 @@
|
|||
route_append_only: no
|
||||
rule_append_only: yes
|
||||
|
||||
- name: Verify nmcli connection DNS entry
|
||||
- name: Verify nmcli connection DNS entry for IPv4
|
||||
shell: |
|
||||
set -euxo pipefail
|
||||
nmcli connection show {{ interface }} | grep ipv4.dns
|
||||
|
|
@ -72,11 +73,20 @@
|
|||
ignore_errors: yes
|
||||
changed_when: false
|
||||
|
||||
- name: Verify nmcli connection DNS entry for IPv6
|
||||
shell: |
|
||||
set -euxo pipefail
|
||||
nmcli connection show {{ interface }} | grep ipv6.dns
|
||||
register: ipv6_dns
|
||||
ignore_errors: yes
|
||||
changed_when: false
|
||||
|
||||
- name: "Assert that DNS addresses are configured correctly"
|
||||
assert:
|
||||
that:
|
||||
- "'192.0.2.2' in ipv4_dns.stdout"
|
||||
- "'198.51.100.5' in ipv4_dns.stdout"
|
||||
- "'2001:db8::20' in ipv6_dns.stdout"
|
||||
msg: "DNS addresses are configured incorrectly"
|
||||
|
||||
- name: "Assert that DNS search domains are configured correctly"
|
||||
|
|
@ -84,6 +94,8 @@
|
|||
that:
|
||||
- "'example.com' in ipv4_dns.stdout"
|
||||
- "'example.org' in ipv4_dns.stdout"
|
||||
- "'example.com' in ipv6_dns.stdout"
|
||||
- "'example.org' in ipv6_dns.stdout"
|
||||
msg: "DNS search domains are configured incorrectly"
|
||||
|
||||
- name: "Assert that DNS options are configured correctly"
|
||||
|
|
@ -91,6 +103,8 @@
|
|||
that:
|
||||
- "'rotate' in ipv4_dns.stdout"
|
||||
- "'timeout:1' in ipv4_dns.stdout"
|
||||
- "'rotate' in ipv6_dns.stdout"
|
||||
- "'timeout:1' in ipv6_dns.stdout"
|
||||
msg: "DNS options are configured incorrectly"
|
||||
|
||||
- import_playbook: down_profile.yml
|
||||
|
|
|
|||
|
|
@ -3321,6 +3321,78 @@ class TestValidator(unittest.TestCase):
|
|||
validator.validate(true_testcase_12)["dns_options"], ["use-vc"]
|
||||
)
|
||||
|
||||
def test_ipv4_dns_without_ipv4_config(self):
|
||||
"""
|
||||
Test that configuring IPv4 DNS is not allowed when IPv4 is disabled.
|
||||
"""
|
||||
validator = network_lsr.argument_validator.ArgValidator_ListConnections()
|
||||
ipv4_dns_without_ipv4_config = [
|
||||
{
|
||||
"name": "test_ipv4_dns",
|
||||
"type": "ethernet",
|
||||
"ip": {
|
||||
"auto6": True,
|
||||
"dhcp4": False,
|
||||
"dns": ["198.51.100.5"],
|
||||
},
|
||||
}
|
||||
]
|
||||
self.assertRaises(
|
||||
ValidationError,
|
||||
validator.validate_connection_one,
|
||||
"nm",
|
||||
validator.validate(ipv4_dns_without_ipv4_config),
|
||||
0,
|
||||
)
|
||||
|
||||
def test_ipv6_dns_without_ipv6_config(self):
|
||||
"""
|
||||
Test that configuring IPv6 DNS is not allowed when IPv6 is disabled.
|
||||
"""
|
||||
validator = network_lsr.argument_validator.ArgValidator_ListConnections()
|
||||
ipv6_dns_without_ipv6_config = [
|
||||
{
|
||||
"name": "test_ipv6_dns",
|
||||
"type": "ethernet",
|
||||
"ip": {
|
||||
"ipv6_disabled": True,
|
||||
"dhcp4": True,
|
||||
"dns": ["2001:db8::20"],
|
||||
},
|
||||
}
|
||||
]
|
||||
self.assertRaises(
|
||||
ValidationError,
|
||||
validator.validate_connection_one,
|
||||
"nm",
|
||||
validator.validate(ipv6_dns_without_ipv6_config),
|
||||
0,
|
||||
)
|
||||
|
||||
def test_ipv6_dns_options_without_ipv6_config(self):
|
||||
"""
|
||||
Test that configuring IPv6 DNS options is not allowed when IPv6 is disabled.
|
||||
"""
|
||||
validator = network_lsr.argument_validator.ArgValidator_ListConnections()
|
||||
ipv6_dns_options_without_ipv6_config = [
|
||||
{
|
||||
"name": "test_ipv6_dns",
|
||||
"type": "ethernet",
|
||||
"ip": {
|
||||
"ipv6_disabled": True,
|
||||
"dhcp4": True,
|
||||
"dns_options": ["ip6-bytestring"],
|
||||
},
|
||||
}
|
||||
]
|
||||
self.assertRaises(
|
||||
ValidationError,
|
||||
validator.validate_connection_one,
|
||||
"nm",
|
||||
validator.validate(ipv6_dns_options_without_ipv6_config),
|
||||
0,
|
||||
)
|
||||
|
||||
def test_set_deprecated_master(self):
|
||||
"""
|
||||
When passing the deprecated "master" it is updated to "controller".
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue