├── .fmf └── version ├── unittests ├── __init__.py ├── configuration │ ├── __init__.py │ ├── test_bool_option.py │ ├── test_ip_option.py │ ├── test_string_option.py │ ├── test_static_servers_option.py │ └── test_syslog_option.py ├── dns_managers │ ├── __init__.py │ └── test_unbound_manager.py └── network_objects │ └── __init__.py ├── distribution ├── dnsconfd.conf ├── README.md ├── dnsconfd.sysconfig ├── unbound-dnsconfd.conf ├── dnsconfd-tmpfiles.conf ├── dnsconfd-unbound-tmpfiles.conf ├── dnsconfd.service.d-unbound.conf ├── micro-dnsconfd.sysconfig ├── dracut_module │ ├── micro_dnsconfd_no_fail.conf │ ├── unbound_non_empty.conf │ └── module-setup.sh ├── com.redhat.dnsconfd.service ├── dnsconfd.sysusers ├── dnsconfd.fc ├── dnsconfd.rules ├── micro-dnsconfd.service ├── dnsconfd.service ├── dnsconfd-cleanup.sh ├── dnsconfd-prepare.sh ├── LICENSE ├── dnsconfd-reload.8 ├── dnsconfd-status.8 ├── dnsconfd-config.8 └── com.redhat.dnsconfd.conf ├── LICENSE ├── .gitignore ├── tests ├── main.fmf ├── dns-over-tls │ ├── ca_cert.pem │ ├── ca_cert2.pem │ ├── main.fmf │ └── expected_status.json ├── globalconfig │ ├── ca_cert.pem │ ├── main.fmf │ └── test.sh ├── static_servers │ ├── ca_cert.pem │ ├── dnsconfd.conf │ ├── dnsconfd-wrong.conf │ ├── main.fmf │ ├── dnsconfd-second.conf │ └── expected_status.json ├── initramfs_support │ ├── ca_cert.pem │ ├── main.fmf │ ├── test-resolve.service │ ├── module-setup.sh │ └── test.sh ├── prioritize_encrypted_protocols │ ├── ca_cert.pem │ ├── main.fmf │ └── expected_status.json ├── ratool_entry.sh ├── dhcp_entry.sh ├── bind_entry.sh ├── dnsmasq_entry.sh ├── uri_parsing │ ├── expected_status4.json │ ├── main.fmf │ ├── expected_status1.json │ ├── expected_status3.json │ └── expected_status2.json ├── bind_zones │ ├── dsset-com. │ ├── dsset-example.com. │ ├── README.md │ ├── Kcom.+008+23814.key │ ├── Kexample.com.+008+42430.key │ ├── com │ ├── example.com │ ├── Kcom.+008+01312.key │ ├── Kexample.com.+008+64519.key │ ├── Kcom.+008+23814.private │ ├── Kexample.com.+008+42430.private │ ├── Kcom.+008+01312.private │ └── Kexample.com.+008+64519.private ├── logging │ ├── main.fmf │ ├── test.sh │ └── rsyslog.conf ├── dnssec │ ├── main.fmf │ ├── expected_status.json │ ├── root.key │ └── test.sh ├── listen_address │ ├── main.fmf │ ├── expected_status.json │ └── test.sh ├── reverse_records │ ├── main.fmf │ └── expected_status.json ├── idna │ └── main.fmf ├── bad_inputs │ └── main.fmf ├── priority │ ├── main.fmf │ ├── expected_status1.json │ ├── expected_status3.json │ └── expected_status2.json ├── autostart │ ├── main.fmf │ ├── expected_status.json │ └── expected_status2.json ├── start │ ├── main.fmf │ └── test.sh ├── start_issue │ ├── main.fmf │ └── test.sh ├── basic │ ├── main.fmf │ ├── expected_status.json │ └── test.sh ├── ipv4_ipv6_routing │ └── main.fmf ├── modes │ ├── main.fmf │ ├── expected_status3.json │ ├── expected_status2.json │ └── expected_status1.json ├── routing │ └── main.fmf ├── invalid_config │ ├── main.fmf │ └── test.sh ├── syslog_logging │ ├── main.fmf │ ├── test.sh │ └── rsyslog.conf ├── duplicate_servers │ ├── main.fmf │ └── expected_status.json ├── unusual_port │ ├── main.fmf │ ├── expected_status1.json │ └── expected_status2.json ├── build_images.sh ├── reload │ ├── main.fmf │ ├── expected_status.json │ └── test.sh ├── vpn_entry.sh ├── dbus-status │ ├── main.fmf │ └── test.sh ├── dhcp │ ├── main.fmf │ └── expected_status.json ├── unbound-stop-recovery │ ├── main.fmf │ ├── expected_status.json │ └── test.sh ├── cleanup │ ├── main.fmf │ ├── expected_status.json │ └── test.sh ├── vpn │ ├── main.fmf │ ├── expected_status1.json │ ├── expected_status3.json │ └── expected_status2.json ├── two-interfaces │ ├── main.fmf │ ├── expected_status.json │ └── test.sh ├── dhcpd-empty.conf ├── wireless │ ├── main.fmf │ └── expected_status.json ├── dhcpd-common.conf ├── radvd.conf ├── dnsconfd_helper_functions.sh ├── build_package.sh ├── build_ostree.sh ├── named_certs │ ├── my_signed_cert2.pem │ ├── ca_cert2.pem │ ├── my_cert_req.pem │ ├── ca_private_key2.key │ ├── my_private_key2.pem │ ├── my_signed_cert.pem │ ├── ca_cert.pem │ ├── ca_private_key.pem │ └── my_private_key.pem ├── dnsconfd-test-utilities.Dockerfile ├── dnsconfd.Dockerfile ├── vpn.conf ├── named.conf └── named2.conf ├── config.flake8 ├── docs ├── modules.rst ├── index.rst ├── dnsconfd.input_modules.rst ├── dnsconfd.dns_managers.rst ├── dnsconfd.network_objects.rst ├── generate_fsm.py ├── dnsconfd.fsm.rst ├── dnsconfd.rst ├── conf.py └── com.redhat.dnsconfd.md ├── .copr └── Makefile ├── requires.txt ├── micro-dnsconfd ├── file-utilities.h ├── dbus-handling.h ├── tests │ ├── test-uri-parsing.h │ ├── test-nm-config-parsing.h │ ├── runtests.c │ └── test-uri-parsing.c ├── output-handling.h ├── arg-parsing.h ├── nm-config-parsing.h ├── uri-parsing.h ├── file-utilities.c ├── output-handling.c ├── arg-parsing.c ├── CMakeLists.txt ├── micro-dnsconfd.c └── dbus-handling.c ├── plans ├── imagemode.fmf ├── unit.fmf ├── integration.fmf └── distribution.fmf ├── dnsconfd ├── dns_managers │ ├── __init__.py │ └── dns_manager.py ├── fsm │ ├── __init__.py │ ├── transitions │ │ ├── __init__.py │ │ └── transition_implementations.py │ ├── context_event.py │ ├── exit_code_handler.py │ └── context_state.py ├── input_modules │ └── __init__.py ├── __init__.py ├── network_objects │ ├── __init__.py │ └── dns_protocol.py ├── exit_code.py ├── configuration │ ├── __init__.py │ ├── bool_option.py │ ├── ip_option.py │ ├── string_option.py │ ├── option.py │ └── syslog_option.py ├── resolving_mode.py └── network_manager.py ├── setup.py ├── TODO ├── bin └── dnsconfd ├── .packit.yaml └── README.md /.fmf/version: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /unittests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /distribution/dnsconfd.conf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ./distribution/LICENSE -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | *.rpm 3 | -------------------------------------------------------------------------------- /distribution/README.md: -------------------------------------------------------------------------------- 1 | ../README.md -------------------------------------------------------------------------------- /tests/main.fmf: -------------------------------------------------------------------------------- 1 | test: ./test.sh 2 | -------------------------------------------------------------------------------- /unittests/configuration/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /unittests/dns_managers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /unittests/network_objects/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/dns-over-tls/ca_cert.pem: -------------------------------------------------------------------------------- 1 | ../named_certs/ca_cert.pem -------------------------------------------------------------------------------- /tests/dns-over-tls/ca_cert2.pem: -------------------------------------------------------------------------------- 1 | ../named_certs/ca_cert2.pem -------------------------------------------------------------------------------- /tests/globalconfig/ca_cert.pem: -------------------------------------------------------------------------------- 1 | ../named_certs/ca_cert.pem -------------------------------------------------------------------------------- /tests/static_servers/ca_cert.pem: -------------------------------------------------------------------------------- 1 | ../named_certs/ca_cert.pem -------------------------------------------------------------------------------- /tests/initramfs_support/ca_cert.pem: -------------------------------------------------------------------------------- 1 | ../named_certs/ca_cert.pem -------------------------------------------------------------------------------- /tests/prioritize_encrypted_protocols/ca_cert.pem: -------------------------------------------------------------------------------- 1 | ../named_certs/ca_cert.pem -------------------------------------------------------------------------------- /tests/ratool_entry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | radvd -n -C /radvd.conf -m stderr 4 | -------------------------------------------------------------------------------- /distribution/dnsconfd.sysconfig: -------------------------------------------------------------------------------- 1 | OPTIONS="" 2 | STDERR_LOG=no 3 | JOURNAL_LOG=yes 4 | -------------------------------------------------------------------------------- /distribution/unbound-dnsconfd.conf: -------------------------------------------------------------------------------- 1 | server: 2 | include: /run/dnsconfd/unbound.conf 3 | -------------------------------------------------------------------------------- /tests/dhcp_entry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | /usr/sbin/dhcpd -f -cf "$@" 6 | -------------------------------------------------------------------------------- /config.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 79 3 | per-file-ignores = __init__.py:F401 4 | -------------------------------------------------------------------------------- /distribution/dnsconfd-tmpfiles.conf: -------------------------------------------------------------------------------- 1 | D /run/dnsconfd 0755 dnsconfd dnsconfd - 2 | -------------------------------------------------------------------------------- /tests/bind_entry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | /usr/sbin/named -u named -g -c "$@" 6 | -------------------------------------------------------------------------------- /distribution/dnsconfd-unbound-tmpfiles.conf: -------------------------------------------------------------------------------- 1 | f+ /run/dnsconfd/unbound.conf 0664 dnsconfd dnsconfd - 2 | -------------------------------------------------------------------------------- /distribution/dnsconfd.service.d-unbound.conf: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStopPost=-/usr/bin/dnsconfd reload 3 | -------------------------------------------------------------------------------- /distribution/micro-dnsconfd.sysconfig: -------------------------------------------------------------------------------- 1 | OPTIONS="-u /run/dnsconfd/unbound.conf -r /etc/resolv.conf" 2 | -------------------------------------------------------------------------------- /docs/modules.rst: -------------------------------------------------------------------------------- 1 | dnsconfd 2 | ======== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | dnsconfd 8 | -------------------------------------------------------------------------------- /tests/dnsmasq_entry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | /usr/sbin/dnsmasq -d --no-resolv --no-hosts "$@" 6 | -------------------------------------------------------------------------------- /tests/uri_parsing/expected_status4.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{},"mode":"backup","servers":[],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /tests/static_servers/dnsconfd.conf: -------------------------------------------------------------------------------- 1 | static_servers: 2 | - address: 192.168.6.3 3 | protocol: "dns+tls" 4 | -------------------------------------------------------------------------------- /tests/bind_zones/dsset-com.: -------------------------------------------------------------------------------- 1 | com. IN DS 1312 8 2 732C15075835E66D66197513F1A8AD1E9DAECEE6EF06BE329C232A9E 212C6C9D 2 | -------------------------------------------------------------------------------- /tests/static_servers/dnsconfd-wrong.conf: -------------------------------------------------------------------------------- 1 | static_servers: 2 | .: 3 | - address: 192.168. 4 | protocol: "DoT" 5 | -------------------------------------------------------------------------------- /.copr/Makefile: -------------------------------------------------------------------------------- 1 | outdir?=. 2 | srpm: 3 | rpm -q git-core packit || dnf install -y git-core packit 4 | packit srpm --output=$(outdir) 5 | -------------------------------------------------------------------------------- /tests/bind_zones/dsset-example.com.: -------------------------------------------------------------------------------- 1 | example.com. IN DS 64519 8 2 8504640FDBA82D2A32AA0D53ECCE756D1A1DA77FDCE6F5E3CFFC9981 8C70C1E5 2 | -------------------------------------------------------------------------------- /requires.txt: -------------------------------------------------------------------------------- 1 | graphviz~=0.20.1 2 | dnsconfd~=1.6.0 3 | pytest~=7.4.3 4 | PyGObject~=3.48.2 5 | PyYAML~=6.0.1 6 | setuptools~=69.0.3 7 | idna~=3.7 -------------------------------------------------------------------------------- /micro-dnsconfd/file-utilities.h: -------------------------------------------------------------------------------- 1 | #ifndef FILE_UTILITES_H 2 | #define FILE_UTILITES_H 3 | 4 | const char *get_best_ca_bundle(); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /tests/initramfs_support/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test initramfs support of dnsconfd 2 | test: ./test.sh 3 | framework: beakerlib 4 | tag: 5 | - multihost 6 | -------------------------------------------------------------------------------- /plans/imagemode.fmf: -------------------------------------------------------------------------------- 1 | summary: Run distribution tests with tmt 2 | discover: 3 | how: fmf 4 | filter: tag:distribution 5 | execute: 6 | how: tmt 7 | -------------------------------------------------------------------------------- /tests/logging/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test logging options 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /distribution/dracut_module/micro_dnsconfd_no_fail.conf: -------------------------------------------------------------------------------- 1 | [Service] 2 | EnvironmentFile= 3 | Environment="OPTIONS=-u /run/dnsconfd/unbound.conf -r /etc/resolv.conf -n" 4 | -------------------------------------------------------------------------------- /tests/uri_parsing/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test parsing of URIs 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /distribution/dracut_module/unbound_non_empty.conf: -------------------------------------------------------------------------------- 1 | [Unit] 2 | ConditionPathExists=/run/dnsconfd/unbound.conf 3 | [Service] 4 | Environment="DISABLE_UNBOUND_ANCHOR=yes" 5 | -------------------------------------------------------------------------------- /micro-dnsconfd/dbus-handling.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef DBUS_HANDLING_H 4 | #define DBUS_HANDLING_H 5 | 6 | GVariantDict *get_glob_dict(); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /tests/dnssec/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Verify working dnssec validation 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /tests/listen_address/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test listen_address option 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /tests/reverse_records/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test reverse DNS lookup 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /tests/static_servers/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test static_servers option 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /distribution/com.redhat.dnsconfd.service: -------------------------------------------------------------------------------- 1 | [D-BUS Service] 2 | Name=com.redhat.dnsconfd 3 | Exec=/bin/false 4 | User=root 5 | SystemdService=dbus-com.redhat.dnsconfd.service 6 | -------------------------------------------------------------------------------- /tests/idna/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test idna encoding handling in Dnsconfd 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /micro-dnsconfd/tests/test-uri-parsing.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef TEST_URI_PARSING_H 4 | #define TEST_URI_PARSING_H 5 | 6 | Suite *uri_parsing_suite(); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /tests/bad_inputs/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test various potentially problematic inputs 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /tests/static_servers/dnsconfd-second.conf: -------------------------------------------------------------------------------- 1 | static_servers: 2 | - address: 192.168.6.10 3 | - address: 192.168.6.30 4 | routing_domains: 5 | - second-domain.com 6 | -------------------------------------------------------------------------------- /tests/priority/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Verify Dnsconfd works properly with priority field 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /dnsconfd/dns_managers/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Subpackage for classes managing DNS caching services 3 | """ 4 | 5 | from .dns_manager import DnsManager 6 | from .unbound_manager import UnboundManager 7 | -------------------------------------------------------------------------------- /micro-dnsconfd/tests/test-nm-config-parsing.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef TEST_NM_CONFIG_PARSING_H 4 | #define TEST_NM_CONFIG_PARSING_H 5 | 6 | Suite *nm_config_parsing_suite(); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /tests/autostart/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test whether NetworkManager can trigger start of stopped dnsconfd 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /distribution/dnsconfd.sysusers: -------------------------------------------------------------------------------- 1 | #Type Name ID GECOS Home directory Shell 2 | u dnsconfd - "Dnsconfd local DNS cache configurator" - /sbin/nologin 3 | -------------------------------------------------------------------------------- /micro-dnsconfd/output-handling.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef OUTPUT_HANDLING_H 4 | #define OUTPUT_HANDLING_H 5 | 6 | unsigned char handle_output(char *filename, GString *content); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /tests/start/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Start the service and verify that it is running correctly 2 | test: ./test.sh 3 | framework: beakerlib 4 | tag: 5 | - distribution 6 | recommend: 7 | - dnsconfd 8 | - audit 9 | -------------------------------------------------------------------------------- /tests/start_issue/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Start container, break unbound and verify that dnsconfd shuts down 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /tests/basic/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Start container, set 1 DNS server and verify that dnsconfd handled the update 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /tests/ipv4_ipv6_routing/main.fmf: -------------------------------------------------------------------------------- 1 | summary: | 2 | verify that ipv4 and ipv6 mixed routing works as expected 3 | test: ./test.sh 4 | framework: beakerlib 5 | recommend: 6 | - podman 7 | tag: 8 | - integration 9 | -------------------------------------------------------------------------------- /tests/modes/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Start container, set 1 DNS server and verify that dnsconfd handled the update 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /tests/routing/main.fmf: -------------------------------------------------------------------------------- 1 | summary: | 2 | Test whether dnsconfd is able to properly create routes to DNS servers 3 | test: ./test.sh 4 | framework: beakerlib 5 | recommend: 6 | - podman 7 | tag: 8 | - integration 9 | -------------------------------------------------------------------------------- /tests/dns-over-tls/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Start container, set 1 DNS server and verify that dnsconfd handled the update 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /tests/invalid_config/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Provide invalid config and verify that dnsconfd handles situation correctly 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /tests/prioritize_encrypted_protocols/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Verify Dnsconfd prioritizes servers that support encryption 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /tests/syslog_logging/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Configure syslog logging and verify that it is working 2 | test: ./test.sh 3 | framework: beakerlib 4 | tag: 5 | - distribution 6 | recommend: 7 | - dnsconfd 8 | - rsyslog 9 | -------------------------------------------------------------------------------- /tests/duplicate_servers/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Verify that dnsconfd can handle connection to one network through 2 interfaces 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /dnsconfd/fsm/__init__.py: -------------------------------------------------------------------------------- 1 | """ Subpackage containing classes managing execution flow """ 2 | 3 | from .context_event import ContextEvent 4 | from .context_state import ContextState 5 | from .dnsconfd_context import DnsconfdContext 6 | -------------------------------------------------------------------------------- /dnsconfd/input_modules/__init__.py: -------------------------------------------------------------------------------- 1 | """ Subpackage for classes that handle input into Dnsconfd """ 2 | 3 | from .resolve_dbus_interface import ResolveDbusInterface 4 | from .dnsconfd_dbus_interface import DnsconfdDbusInterface 5 | -------------------------------------------------------------------------------- /tests/globalconfig/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test global DNS config and ensure that there is no attempt to contact different servers 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /tests/unusual_port/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Start container, set 1 DNS server listening on unusual port and verify resolution works 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /tests/build_images.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | podman build tests -f tests/dnsconfd.Dockerfile -t dnsconfd_testing 6 | podman build tests -f tests/dnsconfd-test-utilities.Dockerfile -t localhost/dnsconfd_utilities:latest 7 | -------------------------------------------------------------------------------- /tests/reload/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Start container, set 1 DNS server, reload dnsconfd and verify status and correct address resolution 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /tests/vpn_entry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | /usr/sbin/openvpn --status-version 2 --suppress-timestamps --cipher AES-256-GCM --data-ciphers AES-256-GCM:AES-128-GCM:AES-256-CBC:AES-128-CBC --config /etc/openvpn/serverudp.conf "$@" 6 | -------------------------------------------------------------------------------- /tests/dbus-status/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Start the service and verify that non-root user can ask its status 2 | test: ./test.sh 3 | framework: beakerlib 4 | tag: 5 | - distribution 6 | recommend: 7 | - dnsconfd 8 | - audit 9 | - dbus-tools 10 | -------------------------------------------------------------------------------- /dnsconfd/__init__.py: -------------------------------------------------------------------------------- 1 | """ Dnsconfd main package """ 2 | 3 | from .exit_code import ExitCode 4 | from .resolving_mode import ResolvingMode 5 | from .system_manager import SystemManager 6 | from .network_manager import NetworkManager 7 | from .cli_commands import CLICommands 8 | -------------------------------------------------------------------------------- /dnsconfd/network_objects/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Subpackage for classes that hold information about network objects 3 | """ 4 | 5 | from .dns_protocol import DnsProtocol 6 | from .server_description import ServerDescription 7 | from .interface_configuration import InterfaceConfiguration 8 | -------------------------------------------------------------------------------- /tests/dhcp/main.fmf: -------------------------------------------------------------------------------- 1 | summary: | 2 | Start the container, connect it to network, wait for it to get configuration from DHCP and verify 3 | correct address resolution 4 | test: ./test.sh 5 | framework: beakerlib 6 | recommend: 7 | - podman 8 | tag: 9 | - integration 10 | -------------------------------------------------------------------------------- /tests/unbound-stop-recovery/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Start container, set 1 DNS server and verify that dnsconfd handled the update, stop unbound, let dnsconfd bring it back up and verify again 2 | test: ./test.sh 3 | framework: beakerlib 4 | recommend: 5 | - podman 6 | tag: 7 | - integration 8 | -------------------------------------------------------------------------------- /dnsconfd/fsm/transitions/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Subpackage for classes implementing transitions of dnsconfd FSM 3 | """ 4 | 5 | from .transition_implementations import TransitionImplementations 6 | from .starting import Starting 7 | from .running import Running 8 | from .stopping import Stopping 9 | -------------------------------------------------------------------------------- /tests/cleanup/main.fmf: -------------------------------------------------------------------------------- 1 | summary: | 2 | Start container, set 1 DNS server, verify correct address resolution, stop Dnsconfd and 3 | verify that system works after our cleanup 4 | test: ./test.sh 5 | framework: beakerlib 6 | recommend: 7 | - podman 8 | tag: 9 | - integration 10 | -------------------------------------------------------------------------------- /tests/vpn/main.fmf: -------------------------------------------------------------------------------- 1 | summary: | 2 | Start the container, connect it to network, wait for it to get configuration from DHCP, connect 3 | it to VPN and verify correct address resolution 4 | test: ./test.sh 5 | framework: beakerlib 6 | recommend: 7 | - podman 8 | tag: 9 | - integration 10 | -------------------------------------------------------------------------------- /tests/static_servers/expected_status.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+tls://192.168.6.3"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":false,"firewall_zone":null,"interface":null,"name":null,"networks":[],"port":853,"protocol":"dns+tls","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /tests/uri_parsing/expected_status1.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /tests/two-interfaces/main.fmf: -------------------------------------------------------------------------------- 1 | summary: | 2 | Start the container, connect it to two networks and set DNS for each of them, verify that DNSCONFD 3 | handled the update and name resolution works as expected 4 | test: ./test.sh 5 | framework: beakerlib 6 | recommend: 7 | - podman 8 | tag: 9 | - integration 10 | -------------------------------------------------------------------------------- /dnsconfd/exit_code.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class ExitCode(Enum): 5 | """ Exit codes used by Dnsconfd """ 6 | GRACEFUL_STOP = 0 7 | SERVICE_FAILURE = 8 8 | DBUS_FAILURE = 9 9 | RESOLV_CONF_FAILURE = 10 10 | CONFIG_FAILURE = 11 11 | ROUTE_FAILURE = 12 12 | BAD_ARGUMENTS = 13 13 | -------------------------------------------------------------------------------- /micro-dnsconfd/arg-parsing.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef ARG_PARSING_H 4 | #define ARG_PARSING_H 5 | 6 | typedef struct arguments { 7 | char *resolvconf; 8 | char *unboundconf; 9 | unsigned char no_error_code; 10 | } arguments; 11 | 12 | error_t parse_args(int argc, char *argv[], arguments *args); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | from setuptools import find_packages 3 | 4 | setup( 5 | name='dnsconfd', 6 | version='1.7.3', 7 | install_requires=[ 8 | 'dbus-python', 9 | 'pyyaml' 10 | ], 11 | packages=find_packages(exclude=["unittests*"]), 12 | scripts=["bin/dnsconfd"], 13 | ) 14 | -------------------------------------------------------------------------------- /tests/dhcpd-empty.conf: -------------------------------------------------------------------------------- 1 | subnet 192.168.6.0 netmask 255.255.255.0 { 2 | option routers 192.168.6.1; 3 | option subnet-mask 255.255.255.0; 4 | option domain-name "test.com"; 5 | option domain-search "test.com"; 6 | range 192.168.6.2 192.168.6.3; 7 | } 8 | -------------------------------------------------------------------------------- /tests/wireless/main.fmf: -------------------------------------------------------------------------------- 1 | summary: | 2 | Start the container, add one normal interface and one mocked wireless interface, set different 3 | DNS servers for each of them and verify that the normal has higher priority than the wireless one. 4 | test: ./test.sh 5 | framework: beakerlib 6 | recommend: 7 | - podman 8 | tag: 9 | - integration 10 | -------------------------------------------------------------------------------- /tests/dhcpd-common.conf: -------------------------------------------------------------------------------- 1 | subnet 192.168.6.0 netmask 255.255.255.0 { 2 | option routers 192.168.6.1; 3 | option subnet-mask 255.255.255.0; 4 | option domain-name "test.com"; 5 | option domain-name-servers 192.168.6.3, 192.168.6.4; 6 | range 192.168.6.2 192.168.6.3; 7 | } 8 | -------------------------------------------------------------------------------- /tests/radvd.conf: -------------------------------------------------------------------------------- 1 | interface eth0 2 | { 3 | AdvSendAdvert on; 4 | MinRtrAdvInterval 30; 5 | MaxRtrAdvInterval 100; 6 | prefix 2001:db8::/64 7 | { 8 | AdvOnLink on; 9 | AdvAutonomous on; 10 | AdvRouterAddr off; 11 | }; 12 | RDNSS 2001:db8::3 { }; 13 | }; 14 | -------------------------------------------------------------------------------- /tests/dnsconfd_helper_functions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | jq_filter_customized() { 4 | jq -c -S ". | {service, mode, cache_config, servers: .servers | sort_by(\"address\") | map({$1})}" 5 | } 6 | 7 | jq_filter_general() { 8 | jq_filter_customized 'address, protocol, port, interface, routing_domains, search_domains, networks, firewall_zone, dnssec, name' 9 | } 10 | -------------------------------------------------------------------------------- /tests/basic/expected_status.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3"],"6.168.192.in-addr.arpa":["dns+udp://192.168.6.3"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /tests/cleanup/expected_status.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3"],"6.168.192.in-addr.arpa":["dns+udp://192.168.6.3"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /tests/dnssec/expected_status.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3"],"6.168.192.in-addr.arpa":["dns+udp://192.168.6.3"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /tests/reload/expected_status.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3"],"6.168.192.in-addr.arpa":["dns+udp://192.168.6.3"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /tests/autostart/expected_status.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3"],"6.168.192.in-addr.arpa":["dns+udp://192.168.6.3"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /tests/autostart/expected_status2.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.4"],"6.168.192.in-addr.arpa":["dns+udp://192.168.6.4"]},"mode":"backup","servers":[{"address":"192.168.6.4","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /tests/bind_zones/README.md: -------------------------------------------------------------------------------- 1 | Commands used: 2 | 3 | ``dnssec-keygen -a RSASHA256 -b 2048 -n ZONE com`` 4 | 5 | ``dnssec-keygen -f KSK -a RSASHA256 -b 4096 -n ZONE com`` 6 | 7 | ``dnssec-signzone -3 $(head -c 1000 /dev/random | sha256sum | cut -b 1-16) -A -N INCREMENT -o com -t com`` 8 | 9 | not-working.example.com RRSIG was manually broken so we can test validation failure 10 | -------------------------------------------------------------------------------- /tests/duplicate_servers/expected_status.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.7.4"],"5.168.192.in-addr.arpa":["dns+udp://192.168.7.4"]},"mode":"backup","servers":[{"address":"192.168.7.4","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.5.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /tests/listen_address/expected_status.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3"],"6.168.192.in-addr.arpa":["dns+udp://192.168.6.3"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /tests/initramfs_support/test-resolve.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Try to resolve name 3 | Wants=network-online.target 4 | After=network-online.target 5 | Before=initrd-switch-root.target 6 | Before=initrd.target 7 | After=sysinit.target 8 | 9 | [Service] 10 | Type=oneshot 11 | ExecStart=/usr/bin/getent hosts server.example.com 12 | 13 | [Install] 14 | WantedBy=sysinit.target 15 | -------------------------------------------------------------------------------- /tests/unbound-stop-recovery/expected_status.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3"],"6.168.192.in-addr.arpa":["dns+udp://192.168.6.3"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /tests/unusual_port/expected_status1.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3:73"],"6.168.192.in-addr.arpa":["dns+udp://192.168.6.3:73"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.0/24"],"port":73,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /micro-dnsconfd/nm-config-parsing.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifndef NM_CONFIG_PARSING_H_ 5 | #define NM_CONFIG_PARSING_H_ 6 | 7 | GString *get_unbound_conf_string(GVariantDict *glob_dict, 8 | const char *fallback_ca, FILE *log_file); 9 | GString *get_resolv_conf_string(GVariantDict *glob_dict, FILE *log_file); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /tests/dns-over-tls/expected_status.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+tls://192.168.6.3#named"],"6.168.192.in-addr.arpa":["dns+tls://192.168.6.3#named"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":"eth0","name":"named","networks":["192.168.6.0/24"],"port":853,"protocol":"dns+tls","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /distribution/dnsconfd.fc: -------------------------------------------------------------------------------- 1 | /usr/bin/dnsconfd gen_context(system_u:object_r:dnsconfd_exec_t,s0) 2 | /usr/bin/micro-dnsconfd gen_context(system_u:object_r:dnsconfd_exec_t,s0) 3 | /usr/libexec/dnsconfd-take-resolvconf.sh gen_context(system_u:object_r:dnsconfd_init_exec_t,s0) 4 | /run/dnsconfd(/.*)? gen_context(system_u:object_r:dnsconfd_var_run_t,s0) 5 | -------------------------------------------------------------------------------- /micro-dnsconfd/uri-parsing.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifndef URI_PARSING_H 5 | #define URI_PARSING_H 6 | 7 | unsigned char transform_server_string(gchar *server_string, 8 | unsigned char *is_server_tls, 9 | GString *unbound_config_string, 10 | FILE *log_file); 11 | #endif 12 | -------------------------------------------------------------------------------- /dnsconfd/configuration/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Subpackage for classes parsing configuration 3 | """ 4 | 5 | from .option import Option 6 | from .string_option import StringOption 7 | from .ip_option import IpOption 8 | from .static_servers_option import StaticServersOption 9 | from .bool_option import BoolOption 10 | from .syslog_option import SyslogOption 11 | from .dnsconfd_argument_parser import DnsconfdArgumentParser 12 | -------------------------------------------------------------------------------- /tests/initramfs_support/module-setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | check() { 4 | require_binaries /usr/bin/getent || return 1 5 | return 0 6 | } 7 | 8 | depends() { 9 | return 0 10 | } 11 | 12 | install() { 13 | inst_simple "$moddir/test-resolve.service" /usr/lib/systemd/system/test-resolve.service 14 | inst_simple /usr/bin/getent 15 | 16 | $SYSTEMCTL -q --root "$initdir" enable test-resolve.service 17 | } 18 | -------------------------------------------------------------------------------- /micro-dnsconfd/tests/runtests.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "test-nm-config-parsing.h" 4 | #include "test-uri-parsing.h" 5 | 6 | int main(void) { 7 | int number_failed; 8 | SRunner *sr; 9 | 10 | sr = srunner_create(uri_parsing_suite()); 11 | srunner_add_suite(sr, nm_config_parsing_suite()); 12 | 13 | srunner_run_all(sr, CK_NORMAL); 14 | number_failed = srunner_ntests_failed(sr); 15 | srunner_free(sr); 16 | return (number_failed != 0); 17 | } 18 | -------------------------------------------------------------------------------- /dnsconfd/fsm/context_event.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | 4 | class ContextEvent: 5 | def __init__(self, name: str, data: object = None): 6 | """ Object representing event meant to be handled by Dnsconfd FSM 7 | 8 | :param name: Name of the event 9 | :type name: str 10 | :param data: Data about event, defaults to None 11 | :type data: object, Optional 12 | """ 13 | self.name: str = name 14 | self.data: Any = data 15 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - Make NetworkManager recognize that dnsconfd manages resolv.conf even without the symlink 2 | - Add option to NetworkManager so it can change dbus name of systemd-resolved 3 | - Until NetworkManager starts to really check whether the service is running, we can not stop 4 | using root, because without it we can not access resolv.conf or any other stub resolv.conf 5 | location 6 | - Improve logging. Improve logging prefixes. 7 | - Add option for altering behaviour while handling wireless interfaces. 8 | -------------------------------------------------------------------------------- /unittests/configuration/test_bool_option.py: -------------------------------------------------------------------------------- 1 | from dnsconfd.configuration import BoolOption 2 | 3 | import pytest 4 | 5 | 6 | @pytest.fixture 7 | def instance(): 8 | ins = BoolOption("test", "test", True) 9 | ins.lgr.disabled = True 10 | return ins 11 | 12 | 13 | @pytest.mark.parametrize("value, result", [ 14 | ("Hello", False), 15 | (True, True), 16 | (False, True) 17 | ]) 18 | def test_validate(value, result, instance): 19 | assert instance.validate(value) == result 20 | -------------------------------------------------------------------------------- /tests/unusual_port/expected_status2.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.4:93"]},"mode":"exclusive","servers":[{"address":"192.168.6.4","dnssec":true,"firewall_zone":null,"interface":null,"name":null,"networks":[],"port":93,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]},{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.0/24"],"port":73,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /micro-dnsconfd/file-utilities.c: -------------------------------------------------------------------------------- 1 | #include "file-utilities.h" 2 | 3 | #include 4 | 5 | const char *get_best_ca_bundle() { 6 | struct stat ca_stat; 7 | 8 | // if dns specific bundle does not exist or is not a regular file 9 | // then use the global one 10 | if (stat("/etc/pki/dns/extracted/pem/tls-ca-bundle.pem", &ca_stat) || 11 | !S_ISREG(ca_stat.st_mode)) { 12 | return "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem"; 13 | } 14 | return "/etc/pki/dns/extracted/pem/tls-ca-bundle.pem"; 15 | } 16 | -------------------------------------------------------------------------------- /distribution/dnsconfd.rules: -------------------------------------------------------------------------------- 1 | polkit.addRule(function(action, subject) { 2 | if (action.id == "org.freedesktop.systemd1.manage-units" && 3 | action.lookup("unit") == "unbound.service" && 4 | subject.user == "dnsconfd") 5 | { 6 | return polkit.Result.YES; 7 | } 8 | }) 9 | polkit.addRule(function(action, subject) { 10 | if (action.id == "org.freedesktop.NetworkManager.network-control" && 11 | subject.user == "dnsconfd") 12 | { 13 | return polkit.Result.YES; 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /tests/build_package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | mkdir SOURCES 6 | cp ./distribution/dnsconfd.sysusers ./SOURCES 7 | rm -rf "$tempdir" 8 | # there is a hidden side effect of bb and that is that it copies sources from 9 | # SOURCES directory into binary rpms, however if they are missing, they 10 | # are not copied and scriptlets are left without them 11 | rpmbuild --define "_topdir $PWD" --build-in-place -bb distribution/dnsconfd.spec 12 | find ./RPMS -name "*.rpm" -exec cp "{}" ./tests \; 13 | rm -rf BUILDROOT RPMS SRPMS SOURCES 14 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. dnsconfd documentation master file, created by 2 | sphinx-quickstart on Tue Aug 8 14:26:11 2023. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to dnsconfd's documentation! 7 | ==================================== 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Contents: 12 | 13 | modules 14 | 15 | Indices and tables 16 | ================== 17 | 18 | * :ref:`genindex` 19 | * :ref:`modindex` 20 | * :ref:`search` 21 | -------------------------------------------------------------------------------- /docs/dnsconfd.input_modules.rst: -------------------------------------------------------------------------------- 1 | dnsconfd.input\_modules package 2 | =============================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | dnsconfd.input\_modules.resolve\_dbus\_interface module 8 | ------------------------------------------------------- 9 | 10 | .. automodule:: dnsconfd.input_modules.resolve_dbus_interface 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: dnsconfd.input_modules 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /tests/uri_parsing/expected_status3.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3","dns+udp://192.168.7.3"]},"mode":"exclusive","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":null,"name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":["example.com","example.org"]},{"address":"192.168.7.3","dnssec":true,"firewall_zone":null,"interface":null,"name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":["example.com","example.org"]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /distribution/micro-dnsconfd.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Minimized native implementation of Dnsconfd 3 | After=network.target dbus.service 4 | Before=network-online.target unbound.service 5 | Requires=dbus.service 6 | Conflicts=systemd-resolved.service dnsconfd.service 7 | 8 | [Service] 9 | Type=oneshot 10 | Group=dnsconfd 11 | ExecStart=/usr/bin/micro-dnsconfd $OPTIONS 12 | RemainAfterExit=yes 13 | EnvironmentFile=/etc/sysconfig/micro-dnsconfd 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | WantedBy=network-online.target 18 | RequiredBy=unbound.service 19 | -------------------------------------------------------------------------------- /distribution/dnsconfd.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Dns local cache services configuration daemon 3 | After=network.target dbus.service 4 | Requires=dbus.service 5 | 6 | [Service] 7 | Type=notify 8 | User=dnsconfd 9 | Group=dnsconfd 10 | SupplementaryGroups=unbound 11 | BusName=com.redhat.dnsconfd 12 | ExecStartPre=+/usr/libexec/dnsconfd-prepare 13 | ExecStart=/usr/bin/dnsconfd $OPTIONS 14 | ExecStopPost=+/usr/libexec/dnsconfd-cleanup 15 | EnvironmentFile=/etc/sysconfig/dnsconfd 16 | 17 | [Install] 18 | WantedBy=multi-user.target 19 | Alias=dbus-com.redhat.dnsconfd.service 20 | -------------------------------------------------------------------------------- /tests/prioritize_encrypted_protocols/expected_status.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+tls://192.168.6.3#named"],"6.168.192.in-addr.arpa":["dns+tls://192.168.6.3#named"]},"mode":"backup","servers":[{"address":"192.168.6.4","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]},{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":"eth0","name":"named","networks":["192.168.6.0/24"],"port":853,"protocol":"dns+tls","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /tests/uri_parsing/expected_status2.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3"],"example.com":["dns+tls://[2001:db8::1]:9000"],"example.org":["dns+tls://[2001:db8::1]:9000"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]},{"address":"2001:db8::1","dnssec":true,"firewall_zone":null,"interface":null,"name":null,"networks":[],"port":9000,"protocol":"dns+tls","routing_domains":["example.com","example.org"],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /tests/wireless/expected_status.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.7.3"],"6.168.192.in-addr.arpa":["dns+udp://192.168.6.3"],"7.168.192.in-addr.arpa":["dns+udp://192.168.7.3"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]},{"address":"192.168.7.3","dnssec":true,"firewall_zone":null,"interface":"eth1","name":null,"networks":["192.168.7.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /unittests/configuration/test_ip_option.py: -------------------------------------------------------------------------------- 1 | from dnsconfd.configuration import IpOption 2 | 3 | import pytest 4 | 5 | 6 | @pytest.fixture 7 | def instance(): 8 | ins = IpOption("test", "test", True) 9 | ins.lgr.disabled = True 10 | return ins 11 | 12 | 13 | @pytest.mark.parametrize("value, result", [ 14 | ("127.0.0.1", True), 15 | ("whatever.1.1.1", False), 16 | ("::1", True), 17 | ("300.0.0.1", False), 18 | (" ", False), 19 | ("2001:0000:130F:0000:0000:09C0:876A:130B", True) 20 | ]) 21 | def test_validate(value, result, instance): 22 | assert instance.validate(value) == result 23 | -------------------------------------------------------------------------------- /tests/bind_zones/Kcom.+008+23814.key: -------------------------------------------------------------------------------- 1 | ; This is a zone-signing key, keyid 23814, for com. 2 | ; Created: 20241213124027 (Fri Dec 13 13:40:27 2024) 3 | ; Publish: 20241213124027 (Fri Dec 13 13:40:27 2024) 4 | ; Activate: 20241213124027 (Fri Dec 13 13:40:27 2024) 5 | com. IN DNSKEY 256 3 8 AwEAAc34hTH+T4ErgCmXJN7HU7NYYUA14jNu72Z9txlnxlim5G1pCLnG Tspk3ATMJnOlKh38/0p1wDTdsmuBz7edY1+HGkctjqLjCFL3Iu/0nxxr FQXI3zwnh6tTtE38Hh02fT+D0ksemlIgJY6LmKLhCJ7AuZXNTOKKZaF7 VhDzYNWt86Z5zC+ifCsU+GafIlMtwpGd2jvWC/C8vbXEMj/njBIgafyv 47Ei4ajnEu5iuSKitYDEhazKNxgtPGezH07AysZ+X3792hPtA9m+8nqw peyrpeGbxeF4FxkY0kfi3AKVN9H+yyaM8GQHe4BhNhD6DEItJ52qz3dp /PVVjcouoCk= 6 | -------------------------------------------------------------------------------- /tests/two-interfaces/expected_status.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3","dns+udp://192.168.7.3"],"6.168.192.in-addr.arpa":["dns+udp://192.168.6.3"],"7.168.192.in-addr.arpa":["dns+udp://192.168.7.3"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]},{"address":"192.168.7.3","dnssec":true,"firewall_zone":null,"interface":"eth1","name":null,"networks":["192.168.7.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /tests/bind_zones/Kexample.com.+008+42430.key: -------------------------------------------------------------------------------- 1 | ; This is a zone-signing key, keyid 42430, for example.com. 2 | ; Created: 20241213123807 (Fri Dec 13 13:38:07 2024) 3 | ; Publish: 20241213123807 (Fri Dec 13 13:38:07 2024) 4 | ; Activate: 20241213123807 (Fri Dec 13 13:38:07 2024) 5 | example.com. IN DNSKEY 256 3 8 AwEAAclh7STnNojoGQOBGvV+6QLVjALTBxnDUT4eLPHIKaNLIh9a8zhF HWbI6q2WVOihb3i8icVt/IRMRgDFnmRHpkL6oh5GmrhPvNfHA62pETqq erf0Jr0a9bnvU95NxoPR0xXASfGnHM5MsYRt+ZmXnAYrgzVhNLrEatOM QSbd854utyOdRTgeJmGQZjGhw1UE7eETuP3qn7HXLnhq4nKVDX0G5Yyn gfG0gqCSQOZpXyCpHE+zIGgZ7VYImZddbpraDIM91Socw0dF9eLxwVC+ 15vDlIihLY/cXmWT/RancZDscoB3K2i2kgNuOcYLo0VNRixcaPe7h4IV NhvCVfoTf88= 6 | -------------------------------------------------------------------------------- /unittests/configuration/test_string_option.py: -------------------------------------------------------------------------------- 1 | from dnsconfd.configuration import StringOption 2 | 3 | import pytest 4 | 5 | 6 | @pytest.fixture 7 | def instance(): 8 | ins = StringOption("test", 9 | "test", 10 | "whatever", 11 | validation=r"text[0-9]*") 12 | ins.lgr.disabled = True 13 | return ins 14 | 15 | 16 | @pytest.mark.parametrize("value, result", [ 17 | ("text", True), 18 | ("text1", True), 19 | ("text12", True), 20 | ("texts", False) 21 | ]) 22 | def test_validate(value, result, instance): 23 | assert instance.validate(value) == result 24 | -------------------------------------------------------------------------------- /dnsconfd/configuration/bool_option.py: -------------------------------------------------------------------------------- 1 | from dnsconfd.configuration import Option 2 | 3 | 4 | class BoolOption(Option): 5 | """ 6 | Boolean configuration option 7 | """ 8 | 9 | def validate(self, value) -> bool: 10 | """ Validate that this value is a boolean 11 | 12 | :param value: given value 13 | :return: True if value is a boolean otherwise False 14 | :rtype: bool 15 | """ 16 | if not isinstance(value, bool): 17 | self.lgr.error("Expected true or false for option %s" 18 | " but %s was given", self.name, value) 19 | return False 20 | 21 | return True 22 | -------------------------------------------------------------------------------- /tests/modes/expected_status3.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3"]},"mode":"exclusive","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":null,"name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]},{"address":"192.168.6.4","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":[".","subdomain.example.com"],"search_domains":["subdomain.example.com"]},{"address":"192.168.6.5","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /tests/vpn/expected_status1.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3","dns+udp://192.168.6.4"],"6.168.192.in-addr.arpa":["dns+udp://192.168.6.3","dns+udp://192.168.6.4"],"test.com":["dns+udp://192.168.6.3","dns+udp://192.168.6.4"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["test.com","."],"search_domains":["test.com"]},{"address":"192.168.6.4","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["test.com","."],"search_domains":["test.com"]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /dnsconfd/resolving_mode.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class ResolvingMode(Enum): 5 | """ Resolving mode which determines how the received servers 6 | should be used 7 | """ 8 | BACKUP = 0 # use interface servers for resolving of everything 9 | PREFER = 1 10 | # only global servers can resolve '.', interface 11 | # servers can resolve only subdomains 12 | EXCLUSIVE = 2 # only global servers can be used for resolving 13 | 14 | def __str__(self): 15 | mode_to_str = { 16 | ResolvingMode.BACKUP: "backup", 17 | ResolvingMode.PREFER: "prefer", 18 | ResolvingMode.EXCLUSIVE: "exclusive" 19 | } 20 | return mode_to_str[self] 21 | -------------------------------------------------------------------------------- /tests/priority/expected_status1.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3"],"subdomain.example.com":["dns+udp://192.168.6.4"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":null,"name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]},{"address":"192.168.6.4","dnssec":true,"firewall_zone":null,"interface":null,"name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":[".","subdomain.example.com"],"search_domains":[]},{"address":"192.168.6.5","dnssec":true,"firewall_zone":null,"interface":null,"name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /dnsconfd/fsm/exit_code_handler.py: -------------------------------------------------------------------------------- 1 | from dnsconfd import ExitCode 2 | 3 | 4 | class ExitCodeHandler: 5 | def __init__(self): 6 | """ Object responsible for handling of dnsconfd exit code """ 7 | self.exit_code = 0 8 | 9 | def set_exit_code(self, code: ExitCode): 10 | """ Set exit code 11 | 12 | :param code: code that should be set if possible, if a code 13 | was already set then calling this has no effect 14 | """ 15 | if self.exit_code == 0: 16 | self.exit_code = code.value 17 | 18 | def get_exit_code(self): 19 | """ Get contained exit code 20 | 21 | :return: Contained exit code 22 | """ 23 | return self.exit_code 24 | -------------------------------------------------------------------------------- /tests/bind_zones/com: -------------------------------------------------------------------------------- 1 | $ORIGIN com. 2 | $TTL 86400 3 | @ IN SOA dns1.com. hostmaster.com. ( 4 | 2001062501 ; serial 5 | 21600 ; refresh after 6 hours 6 | 3600 ; retry after 1 hour 7 | 604800 ; expire after 1 week 8 | 86400 ) ; minimum TTL of 1 day 9 | 10 | 11 | IN NS dns1.com. 12 | example.com. IN NS dns1.example.com. 13 | dns1 IN A 192.168.6.3 14 | dns1.example.com. IN A 192.168.6.3 15 | example.com. IN DS 64519 8 2 8504640FDBA82D2A32AA0D53ECCE756D1A1DA77FDCE6F5E3CFFC9981 8C70C1E5 16 | $INCLUDE "Kcom.+008+01312.key" 17 | $INCLUDE "Kcom.+008+23814.key" 18 | -------------------------------------------------------------------------------- /tests/build_ostree.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | if grep el10 /etc/os-release || grep el9 /etc/os-release; then 5 | dnf -y --setopt=install_weak_deps=False --releasever=/ --installroot="$PWD/tests/baseroot" install dnf system-release openvpn NetworkManager-openvpn selinux-policy selinux-policy-base 6 | cp -r /etc/yum.repos.d "$PWD/tests/baseroot/etc" 7 | if [ -d /var/share/test-artifacts ]; then 8 | mkdir -p "$PWD/tests/baseroot/var/share" 9 | cp -r /var/share/test-artifacts "$PWD/tests/baseroot/var/share" 10 | fi 11 | else 12 | dnf -y --setopt=install_weak_deps=False --use-host-config --installroot="$PWD/tests/baseroot" install dnf system-release openvpn NetworkManager-openvpn selinux-policy selinux-policy-base 13 | fi; 14 | -------------------------------------------------------------------------------- /tests/modes/expected_status2.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3"],"subdomain.example.com":["dns+udp://192.168.6.4"]},"mode":"prefer","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":null,"name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]},{"address":"192.168.6.4","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":[".","subdomain.example.com"],"search_domains":["subdomain.example.com"]},{"address":"192.168.6.5","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /tests/priority/expected_status3.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3","dns+udp://192.168.6.5"],"subdomain.example.com":["dns+udp://192.168.6.4"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":null,"name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]},{"address":"192.168.6.4","dnssec":true,"firewall_zone":null,"interface":null,"name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":[".","subdomain.example.com"],"search_domains":[]},{"address":"192.168.6.5","dnssec":true,"firewall_zone":null,"interface":null,"name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /distribution/dnsconfd-cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$(stat --format %U /etc/resolv.conf)" == "dnsconfd" ]; then 4 | dnsconfd config return_resolvconf 5 | fi 6 | # on systems where local root caching was default and we can not 7 | # change distribution default, attempt to enable the feature 8 | # manually 9 | if [ -f /etc/unbound/conf.d/unbound-local-root.conf.disabled ]; then 10 | mv -f /etc/unbound/conf.d/unbound-local-root.conf.disabled /etc/unbound/conf.d/unbound-local-root.conf 11 | fi 12 | # revert our disabling of unbound-anchor 13 | rm -f /run/unbound/anchor-disable 14 | # revert enablement of as112 domain resolution 15 | if [ -e /etc/unbound/conf.d/dnsconfd-as112.conf ]; then 16 | rm -f /etc/unbound/conf.d/dnsconfd-as112.conf 17 | fi 18 | -------------------------------------------------------------------------------- /docs/dnsconfd.dns_managers.rst: -------------------------------------------------------------------------------- 1 | dnsconfd.dns\_managers package 2 | ============================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | dnsconfd.dns\_managers.dns\_manager module 8 | ------------------------------------------ 9 | 10 | .. automodule:: dnsconfd.dns_managers.dns_manager 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | dnsconfd.dns\_managers.unbound\_manager module 16 | ---------------------------------------------- 17 | 18 | .. automodule:: dnsconfd.dns_managers.unbound_manager 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: dnsconfd.dns_managers 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /tests/dnssec/root.key: -------------------------------------------------------------------------------- 1 | com. IN DNSKEY 257 3 8 AwEAAbR8z/iPgXVjfun6sT/DiAVZrRYjFZSv6V1fXS7XKnv++IlYUCfO boUATUwN+j42okl/QuBw7q0+1cfKoR7t4uVC7qBM9BV1OjRt2dNKsudg u/usuhV1c9fQ+d+dEicgPTHX62tt4pH/N13Xz4WL571yUsezRw/JrxbA gAAiKlxLpn20iryx0ClZ7cUhen4ob5JjJ6oDWv/LuEFDJehMoZc5oKJF 1R9JokUm7NiCU+YLgpY8vDklQZ78ndidPmOksaEDyzZ/zlNvczNEWXD5 RAsCirJ5uK/R6rLGXj0Z0/HjXLG4pzxfwF+QGvRkzgmkhIAc3kYRVp56 pVmMcTo8KRgW4RO5XSUWuYujcucDL5Ynu2wiF2SVOGyOXdbqcPn1+Mqt nFAD244t037K9bwxLPHHj6hK1tmMrbPiM/bZf0bJLhCzDBZMr8m85j+/ Lr5+hD0K8T+0rA6zDehSF4qjeDo/womheIBney+wb3+LDVuwoTj/WZJ8 HOAYQplSehSj95mmd+iTYTce6Pa42eF2ZVoEBKxn/vkQP1KscgA7Zd+p XYIdpKxZzsmrFBSFXuLvLwg0VJnBS7l/4Yy4pDBtg2Ot5nZWkcKamgmJ haFagS7z9nBPL5r4pFbjKN9J3p+YdFinOsFdvnHxKpcPBl512HVQ1/rf ayysPfgfH052DXOx;{id = 1312 (ksk), size = 4096b} 2 | -------------------------------------------------------------------------------- /tests/priority/expected_status2.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3","dns+udp://192.168.6.4","dns+udp://192.168.6.5"],"subdomain.example.com":["dns+udp://192.168.6.4"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":null,"name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]},{"address":"192.168.6.4","dnssec":true,"firewall_zone":null,"interface":null,"name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":[".","subdomain.example.com"],"search_domains":[]},{"address":"192.168.6.5","dnssec":true,"firewall_zone":null,"interface":null,"name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /dnsconfd/configuration/ip_option.py: -------------------------------------------------------------------------------- 1 | import ipaddress 2 | 3 | from dnsconfd.configuration import Option 4 | 5 | 6 | class IpOption(Option): 7 | """ 8 | Ip address configuration option 9 | """ 10 | def validate(self, value) -> bool: 11 | """ Validate that the value is an ip address 12 | 13 | :param value: Value that should be validated 14 | :return: True if value is a string of an ip address, otherwise False 15 | :rtype: bool 16 | """ 17 | try: 18 | ipaddress.ip_address(value) 19 | return True 20 | except ValueError: 21 | self.lgr.error("Value of %s must be an ip address " 22 | "%s was given", self.name, value) 23 | return False 24 | -------------------------------------------------------------------------------- /tests/bind_zones/example.com: -------------------------------------------------------------------------------- 1 | $ORIGIN example.com. 2 | $TTL 86400 3 | @ IN SOA dns1.example.com. hostmaster.example.com. ( 4 | 2001062501 ; serial 5 | 21600 ; refresh after 6 hours 6 | 3600 ; retry after 1 hour 7 | 604800 ; expire after 1 week 8 | 86400 ) ; minimum TTL of 1 day 9 | 10 | 11 | IN NS dns1.example.com. 12 | dns1 IN A 192.168.6.3 13 | server IN A 192.168.6.5 14 | not-working IN A 192.168.6.6 15 | $INCLUDE "Kexample.com.+008+42430.key" 16 | $INCLUDE "Kexample.com.+008+64519.key" 17 | -------------------------------------------------------------------------------- /tests/modes/expected_status1.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3","dns+udp://192.168.6.4","dns+udp://192.168.6.5"],"subdomain.example.com":["dns+udp://192.168.6.4"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":null,"name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]},{"address":"192.168.6.4","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":[".","subdomain.example.com"],"search_domains":["subdomain.example.com"]},{"address":"192.168.6.5","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":[],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /docs/dnsconfd.network_objects.rst: -------------------------------------------------------------------------------- 1 | dnsconfd.network\_objects package 2 | ================================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | dnsconfd.network\_objects.interface\_configuration module 8 | --------------------------------------------------------- 9 | 10 | .. automodule:: dnsconfd.network_objects.interface_configuration 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | dnsconfd.network\_objects.server\_description module 16 | ---------------------------------------------------- 17 | 18 | .. automodule:: dnsconfd.network_objects.server_description 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: dnsconfd.network_objects 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/generate_fsm.py: -------------------------------------------------------------------------------- 1 | import graphviz 2 | 3 | from dnsconfd.fsm.dnsconfd_context import DnsconfdContext 4 | 5 | """ 6 | Use this script to generate graph of Dnsconfd FSM 7 | """ 8 | if __name__ == "__main__": 9 | ctx = DnsconfdContext({"listen_address": "0.0.0.0", 10 | "resolv_conf_path": "/", "resolver_options": "edns0", "dnssec_enabled": True, 11 | "prioritize_wire": True, "handle_routing": True, "static_servers": {}, 12 | "certification_authority": "whatever"}, None) 13 | 14 | g = graphviz.Digraph('G', filename='fsm.gv') 15 | 16 | for (key, transitions) in ctx.transitions.items(): 17 | for (event, (next_state, cb)) in transitions.items(): 18 | g.edge(key.name, next_state.name, label=event) 19 | 20 | g.render() 21 | -------------------------------------------------------------------------------- /distribution/dnsconfd-prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$(stat --format %U /etc/resolv.conf)" != "dnsconfd" ]; then 4 | dnsconfd config take_resolvconf 5 | fi 6 | # on systems where local root caching was default and we can not 7 | # change distribution default, attempt to disable the feature 8 | # manually 9 | if [ -f /etc/unbound/conf.d/unbound-local-root.conf ]; then 10 | mv -f /etc/unbound/conf.d/unbound-local-root.conf /etc/unbound/conf.d/unbound-local-root.conf.disabled 11 | fi 12 | # unbound-anchor checks for this file and will not start if it is present 13 | touch /run/unbound/anchor-disable 14 | # revert enablement of as112 domain resolution 15 | if ! [ -e /etc/unbound/conf.d/dnsconfd-as112.conf ]; then 16 | ln -s /usr/share/unbound/conf.d/unbound-as112-networks.conf /etc/unbound/conf.d/dnsconfd-as112.conf 17 | fi 18 | -------------------------------------------------------------------------------- /dnsconfd/configuration/string_option.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from dnsconfd.configuration import Option 4 | 5 | 6 | class StringOption(Option): 7 | """ String configuration option """ 8 | 9 | def validate(self, value) -> bool: 10 | """ Validate that the value conforms to validation regular expression 11 | 12 | :param value: Value that should be validated 13 | :return: True if the value conforms to validation regular expression, 14 | otherwise False 15 | :rtype: bool 16 | """ 17 | pattern = re.compile(self.validation) 18 | 19 | if pattern.fullmatch(value) is None: 20 | self.lgr.error("Value of %s must conform to regular expression " 21 | " %s, but %s was given", 22 | self.name, pattern.pattern, value) 23 | return False 24 | return True 25 | -------------------------------------------------------------------------------- /tests/reverse_records/expected_status.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3","dns+udp://192.168.6.4","dns+udp://192.168.6.5"],"4.8.8.in-addr.arpa":["dns+udp://192.168.6.5"],"7.168.192.in-addr.arpa":["dns+udp://192.168.6.4"],"8.168.192.in-addr.arpa":["dns+udp://192.168.6.5"],"8.in-addr.arpa":["dns+udp://192.168.6.3"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":null,"name":null,"networks":["8.0.0.0/8"],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]},{"address":"192.168.6.4","dnssec":true,"firewall_zone":null,"interface":null,"name":null,"networks":["192.168.7.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]},{"address":"192.168.6.5","dnssec":true,"firewall_zone":null,"interface":null,"name":null,"networks":["192.168.8.0/24","8.8.4.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["."],"search_domains":[]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /tests/bind_zones/Kcom.+008+01312.key: -------------------------------------------------------------------------------- 1 | ; This is a key-signing key, keyid 1312, for com. 2 | ; Created: 20241213124039 (Fri Dec 13 13:40:39 2024) 3 | ; Publish: 20241213124039 (Fri Dec 13 13:40:39 2024) 4 | ; Activate: 20241213124039 (Fri Dec 13 13:40:39 2024) 5 | com. IN DNSKEY 257 3 8 AwEAAbR8z/iPgXVjfun6sT/DiAVZrRYjFZSv6V1fXS7XKnv++IlYUCfO boUATUwN+j42okl/QuBw7q0+1cfKoR7t4uVC7qBM9BV1OjRt2dNKsudg u/usuhV1c9fQ+d+dEicgPTHX62tt4pH/N13Xz4WL571yUsezRw/JrxbA gAAiKlxLpn20iryx0ClZ7cUhen4ob5JjJ6oDWv/LuEFDJehMoZc5oKJF 1R9JokUm7NiCU+YLgpY8vDklQZ78ndidPmOksaEDyzZ/zlNvczNEWXD5 RAsCirJ5uK/R6rLGXj0Z0/HjXLG4pzxfwF+QGvRkzgmkhIAc3kYRVp56 pVmMcTo8KRgW4RO5XSUWuYujcucDL5Ynu2wiF2SVOGyOXdbqcPn1+Mqt nFAD244t037K9bwxLPHHj6hK1tmMrbPiM/bZf0bJLhCzDBZMr8m85j+/ Lr5+hD0K8T+0rA6zDehSF4qjeDo/womheIBney+wb3+LDVuwoTj/WZJ8 HOAYQplSehSj95mmd+iTYTce6Pa42eF2ZVoEBKxn/vkQP1KscgA7Zd+p XYIdpKxZzsmrFBSFXuLvLwg0VJnBS7l/4Yy4pDBtg2Ot5nZWkcKamgmJ haFagS7z9nBPL5r4pFbjKN9J3p+YdFinOsFdvnHxKpcPBl512HVQ1/rf ayysPfgfH052DXOx 6 | -------------------------------------------------------------------------------- /tests/bind_zones/Kexample.com.+008+64519.key: -------------------------------------------------------------------------------- 1 | ; This is a key-signing key, keyid 64519, for example.com. 2 | ; Created: 20241213123823 (Fri Dec 13 13:38:23 2024) 3 | ; Publish: 20241213123823 (Fri Dec 13 13:38:23 2024) 4 | ; Activate: 20241213123823 (Fri Dec 13 13:38:23 2024) 5 | example.com. IN DNSKEY 257 3 8 AwEAAa2tQbssQBKawJUa4VMjx9GTMHm58butmY3cyQWJY/BojqcWY0oj H1Qe5YZ+vGVgK6o/PWJkQVKrMYGgEMQhOXtRGp4Hr+QseGLs+/EQt23I kkVXSHdY4fANDboimorEuuh2iIyLnXXg0R0moC2xO2VdHE/4A7JsTGsr OGCBctBA9aoqupLsYDGFNBbYGhVXc3z6tZXwbPqKTQx+kBHDFD4TULdQ zQ5ObuX900QNzF/WnL97NKPUaOPV6MMJ6EtPvu75mKYtbgdppmmQXe/f 6+uYfguUtoolKc3h98Jjpr7jcIGrVs1Etj1ozv7wQo7bhKUoXsFvEfQ/ LQifRJvl6m/vLu0fRyvB0uHYbGowGosrA4jMIuHIL+Jv/hKMsGdJShmZ viWmMU9zaareZpSl7DBhyWhQgRovBFFoIdNww2kelm82sR0R9BmJ6Imf 3i2YZr1Suw/QDW2foVmu3G8yfEuzlRhg6Vs+B630CoA955Nj7uUJoY4i 7r/zjlM12merg81vYqdPnzigR5Bdk6zrkJsiRZWCHHm+YZVcBPvJhBM3 4P+q1Cq7rnM0EK5T+r+IatMvrLK3Dq3G0V5YQGgH0RWRgoD9Lt7ZX5zK N5RIVcYh9pBxXuWhCoaNVZ25rrDPfaQrrRo07AMCRm1G9hyQ3OzEMpXt kNg2+YSHNFd06vuF 6 | -------------------------------------------------------------------------------- /micro-dnsconfd/output-handling.c: -------------------------------------------------------------------------------- 1 | #include "output-handling.h" 2 | 3 | #include 4 | #include 5 | 6 | static unsigned char write_to_file(GString *content, char *path) { 7 | unsigned char print_rc; 8 | unsigned char close_rc; 9 | FILE *opened_file = fopen(path, "w"); 10 | if (!opened_file) { 11 | fprintf(stderr, "Failed to open %s errno %d", path, errno); 12 | return 1; 13 | } 14 | 15 | print_rc = (fprintf(opened_file, "%s", content->str) != strlen(content->str)); 16 | close_rc = fclose(opened_file); 17 | 18 | if (print_rc) { 19 | fprintf(stderr, "Failed to write to %s", path); 20 | return 1; 21 | } else if (close_rc) { 22 | fprintf(stderr, "Failed to close %s", path); 23 | return 1; 24 | } 25 | return 0; 26 | } 27 | 28 | unsigned char handle_output(char *filename, GString *content) { 29 | if (!filename) { 30 | fprintf(stdout, "%s", content->str); 31 | return 0; 32 | } 33 | return write_to_file(content, filename); 34 | } 35 | -------------------------------------------------------------------------------- /distribution/dracut_module/module-setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | check() { 4 | require_binaries micro-dnsconfd || return 1 5 | return 0 6 | } 7 | 8 | depends() { 9 | # because of pid file we need sysusers to create unbound user 10 | echo dbus systemd unbound systemd-sysusers network-manager 11 | return 0 12 | } 13 | 14 | install() { 15 | inst_simple /usr/lib/systemd/system/micro-dnsconfd.service 16 | inst_simple "$moddir/unbound_non_empty.conf" /etc/systemd/system/unbound.service.d/unbound_non_empty.conf 17 | inst_simple "$moddir/micro_dnsconfd_no_fail.conf" /etc/systemd/system/micro-dnsconfd.service.d/micro_dnsconfd_no_fail.conf 18 | inst_simple /usr/lib/sysusers.d/dnsconfd.conf 19 | inst_simple /usr/bin/micro-dnsconfd 20 | inst_simple /usr/lib/tmpfiles.d/dnsconfd.conf 21 | inst_simple /etc/unbound/conf.d/unbound.conf 22 | inst_simple /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem 23 | inst_multiple -o /etc/pki/dns/extracted/pem/* 24 | 25 | $SYSTEMCTL -q --root "$initdir" enable micro-dnsconfd.service 26 | } 27 | -------------------------------------------------------------------------------- /distribution/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2023 Red Hat, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /tests/dhcp/expected_status.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3","dns+udp://192.168.6.4","dns+udp://[2001:db8::3]"],"0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa":["dns+udp://[2001:db8::3]"],"0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa":["dns+udp://[2001:db8::3]"],"6.168.192.in-addr.arpa":["dns+udp://192.168.6.3","dns+udp://192.168.6.4"],"test.com":["dns+udp://192.168.6.3","dns+udp://192.168.6.4","dns+udp://[2001:db8::3]"]},"mode":"backup","servers":[{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["test.com","."],"search_domains":["test.com"]},{"address":"192.168.6.4","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["test.com","."],"search_domains":["test.com"]},{"address":"2001:db8::3","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["2001:db8::/64","fe80::/64"],"port":53,"protocol":"dns+udp","routing_domains":["test.com","."],"search_domains":["test.com"]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /docs/dnsconfd.fsm.rst: -------------------------------------------------------------------------------- 1 | dnsconfd.fsm package 2 | ============================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | dnsconfd.fsm.context\_event module 8 | ------------------------------------------ 9 | 10 | .. automodule:: dnsconfd.fsm.context_event 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | dnsconfd.fsm.context\_state module 16 | ---------------------------------------------- 17 | 18 | .. automodule:: dnsconfd.fsm.context_state 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | dnsconfd.fsm.dnsconfd\_context module 24 | ---------------------------------------------- 25 | 26 | .. automodule:: dnsconfd.fsm.dnsconfd_context 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | dnsconfd.fsm.exit\_code module 32 | ---------------------------------------------- 33 | 34 | .. automodule:: dnsconfd.fsm.exit_code 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | Module contents 40 | --------------- 41 | 42 | .. automodule:: dnsconfd.fsm 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | -------------------------------------------------------------------------------- /dnsconfd/network_objects/dns_protocol.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | from typing import Optional 3 | 4 | 5 | class DnsProtocol(Enum): 6 | """ Dns communication protocols """ 7 | DNS_PLUS_UDP = 0 8 | DNS_PLUS_TCP = 1 9 | DNS_PLUS_TLS = 2 10 | 11 | def __str__(self): 12 | protocol_to_str = {DnsProtocol.DNS_PLUS_UDP: "dns+udp", 13 | DnsProtocol.DNS_PLUS_TCP: "dns+tcp", 14 | DnsProtocol.DNS_PLUS_TLS: "dns+tls"} 15 | return protocol_to_str[self] 16 | 17 | @staticmethod 18 | def from_str(name: str) -> Optional["DnsProtocol"]: 19 | str_to_protocol = {"dns+udp": DnsProtocol.DNS_PLUS_UDP, 20 | "dns+tcp": DnsProtocol.DNS_PLUS_TCP, 21 | "dns+tls": DnsProtocol.DNS_PLUS_TLS} 22 | return str_to_protocol.get(name.lower(), None) 23 | 24 | def get_priority(self): 25 | priority_dict = {DnsProtocol.DNS_PLUS_UDP: 0, 26 | DnsProtocol.DNS_PLUS_TCP: 0, 27 | DnsProtocol.DNS_PLUS_TLS: 1} 28 | return priority_dict[self] 29 | -------------------------------------------------------------------------------- /tests/vpn/expected_status3.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.7.2"],"1.0.8.10.in-addr.arpa":["dns+udp://192.168.7.2"],"30.6.168.192.in-addr.arpa":["dns+udp://192.168.6.3","dns+udp://192.168.6.4"],"6.168.192.in-addr.arpa":["dns+udp://192.168.6.3","dns+udp://192.168.6.4"],"7.168.192.in-addr.arpa":["dns+udp://192.168.7.2"],"test.com":["dns+udp://192.168.6.3","dns+udp://192.168.6.4"],"vpndomain.com":["dns+udp://192.168.7.2"]},"mode":"backup","servers":[{"address":"192.168.7.2","dnssec":true,"firewall_zone":null,"interface":"tun1","name":null,"networks":["10.8.0.1/32","192.168.7.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["vpndomain.com","."],"search_domains":["vpndomain.com"]},{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.30/32","192.168.6.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["test.com","."],"search_domains":["test.com"]},{"address":"192.168.6.4","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.30/32","192.168.6.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["test.com","."],"search_domains":["test.com"]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /tests/vpn/expected_status2.json: -------------------------------------------------------------------------------- 1 | {"cache_config":{".":["dns+udp://192.168.6.3","dns+udp://192.168.6.4"],"1.0.8.10.in-addr.arpa":["dns+udp://192.168.7.2"],"30.6.168.192.in-addr.arpa":["dns+udp://192.168.6.3","dns+udp://192.168.6.4"],"6.168.192.in-addr.arpa":["dns+udp://192.168.6.3","dns+udp://192.168.6.4"],"7.168.192.in-addr.arpa":["dns+udp://192.168.7.2"],"test.com":["dns+udp://192.168.6.3","dns+udp://192.168.6.4"],"vpndomain.com":["dns+udp://192.168.7.2"]},"mode":"backup","servers":[{"address":"192.168.7.2","dnssec":true,"firewall_zone":null,"interface":"tun0","name":null,"networks":["10.8.0.1/32","192.168.7.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["vpndomain.com"],"search_domains":["vpndomain.com"]},{"address":"192.168.6.3","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.30/32","192.168.6.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["test.com","."],"search_domains":["test.com"]},{"address":"192.168.6.4","dnssec":true,"firewall_zone":null,"interface":"eth0","name":null,"networks":["192.168.6.30/32","192.168.6.0/24"],"port":53,"protocol":"dns+udp","routing_domains":["test.com","."],"search_domains":["test.com"]}],"service":"unbound"} 2 | -------------------------------------------------------------------------------- /tests/named_certs/my_signed_cert2.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDCDCCAfCgAwIBAgIUTOsbrhqxcStnWsVcunfXIm9Pti0wDQYJKoZIhvcNAQEL 3 | BQAwGjELMAkGA1UEBhMCVVMxCzAJBgNVBAMMAkNBMB4XDTI1MDQyOTA4MDk0OFoX 4 | DTM1MDQyNzA4MDk0OFowHjELMAkGA1UEBhMCVVMxDzANBgNVBAMMBm5hbWVkMjCC 5 | ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK9GpNN/5pe/iRXl+x41bNTj 6 | XBHB3DtNmKFbYHB/5Rkc0+gZHljL2bP74LhbuLPAYhTfmgZOtJmikwska5IFZg39 7 | OtQzUrq38+LIaZPWVoLF0jXsoHN6SNjMcyhP5i90P0iVcBDiwl6/Xj+xP1nowaRg 8 | hjAXas+PdK+culSFDgjV0KgX/0ZpqsiR+hjU/8s7ez22s6HGeaeO9SQAyMEMncbB 9 | 3sudPDg4KkUuTC8CCT6+bJEb1t5LKjYV9RBm8cl5jwL24w453Xgy+oQj7fGwOKXd 10 | 0RnVgSiqjZs8hPouWmKCenzQu2L2HbhqMCwsvyL8/VQs3mUs1VAamULJze8u4PcC 11 | AwEAAaNCMEAwHQYDVR0OBBYEFHQ+hbBd+0xvjA5M1tBV3+/CXR4FMB8GA1UdIwQY 12 | MBaAFOFZhOBzFhoaAHJ2EE76Yoi7uGCPMA0GCSqGSIb3DQEBCwUAA4IBAQBBv5Ox 13 | A2OvWw3Enh7qhOql0GVVOePdXvMzydaoAtCIp5QDLnIr7FW+kL0MUIfZAY8az+YS 14 | ceijpFvrOc9dnpkhF3eIaI6CZym+ProamiFjz6ZErSN3DCJSTx/eadbaJkjEuJO7 15 | ekfrKVtoETFvEzpcJiBN9WQj7W0G48ZT8atnVur6x/Qbtq6gO8FNj3UzEEjZcmwD 16 | UY+M6LE8WbkFo9qMBckpjrJ4ME4BMy52tKy5BN6PKr8+FXVbVAslLbrfckVGlmI/ 17 | Y3C52IPmgCCfJBbRdQYR7CP7dbT6jbsfY5/ShRGSyvE8LisWwCjtpMzvbUEQo6O6 18 | DgiO24cghIKWYHnH 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /tests/named_certs/ca_cert2.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDFTCCAf2gAwIBAgIUTKz56ni0U7uDyqcSYdQqMGoEZqkwDQYJKoZIhvcNAQEL 3 | BQAwGjELMAkGA1UEBhMCVVMxCzAJBgNVBAMMAkNBMB4XDTI1MDQyOTA4MDUzM1oX 4 | DTM1MDQyNzA4MDUzM1owGjELMAkGA1UEBhMCVVMxCzAJBgNVBAMMAkNBMIIBIjAN 5 | BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyP59zRZKYVyJ/3ui+ninmj+Db1Pe 6 | iHP8AC6TMAxOrVuOrKHfZAFsTWAymaaF6O7NEhT7yzEl6bNKAkf1wpar4brGwu/O 7 | kRTHLZWbJV9+XHcqxXyl9bh0vWpPLz2GdfunxMcoTagCDlj456KcPg6uLaAIDviN 8 | P1626TqlPf+3xmnjbBA09Ck1TLWD/+xFm1XeNJZS0cqRAVx24RwaUAfD8rg42kEW 9 | INKoBi3hYplnkW/tqyVseBRZJPu6kpRLXn5AijjZujRakXkInYGYlz87Fv7YACJq 10 | 3goLyWInOqx811FbMomWcHiUnyQ7E26/kBeN3j6ELP3qIxuN/9YUzA5wCQIDAQAB 11 | o1MwUTAdBgNVHQ4EFgQU4VmE4HMWGhoAcnYQTvpiiLu4YI8wHwYDVR0jBBgwFoAU 12 | 4VmE4HMWGhoAcnYQTvpiiLu4YI8wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B 13 | AQsFAAOCAQEATsqw0tRdgOW9IidoEL1JXI88KWqcwHKkzlUGGuBa83Y3YjqXfoMJ 14 | MrjqVOUr0KEixyGoGD6K9UsL6EXlGLclJJI25BXg5nYQdyrwKAYr8NQk1HL327Zo 15 | uo5zAFJSf5UUAk3sVuHBeE743KOUcfI6tSOKuVRdkcGaE6G1FQIDxJbjzAnPTXNM 16 | 9cd3rcDe+JYwJTboIX2P5s6kDMXouDDhU//xh7Czd4Q9RRwc1FkQunS/wNFu+O4y 17 | ZN49PZmvd5OychcKhUzW3DTzX7OW13SOrNzIQFYiX3j/RmNKR6b0rYdaV/1a8MNL 18 | SjaM2aTT3tzOxnlWZnnI4C75IZI54ek14w== 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /docs/dnsconfd.rst: -------------------------------------------------------------------------------- 1 | dnsconfd package 2 | ================ 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | dnsconfd.network_objects 11 | dnsconfd.dns_managers 12 | dnsconfd.fsm 13 | dnsconfd.input_modules 14 | 15 | Submodules 16 | ---------- 17 | 18 | dnsconfd.argument\_parser module 19 | --------------------------------- 20 | 21 | .. automodule:: dnsconfd.argument_parser 22 | :members: 23 | :undoc-members: 24 | :show-inheritance: 25 | 26 | dnsconfd.cli\_commands module 27 | ------------------------------- 28 | 29 | .. automodule:: dnsconfd.cli_commands 30 | :members: 31 | :undoc-members: 32 | :show-inheritance: 33 | 34 | dnsconfd.network\_manager module 35 | -------------------------------- 36 | 37 | .. automodule:: dnsconfd.network_manager 38 | :members: 39 | :undoc-members: 40 | :show-inheritance: 41 | 42 | dnsconfd.system\_manager module 43 | ------------------------------- 44 | 45 | .. automodule:: dnsconfd.system_manager 46 | :members: 47 | :undoc-members: 48 | :show-inheritance: 49 | 50 | Module contents 51 | --------------- 52 | 53 | .. automodule:: dnsconfd 54 | :members: 55 | :undoc-members: 56 | :show-inheritance: 57 | -------------------------------------------------------------------------------- /unittests/configuration/test_static_servers_option.py: -------------------------------------------------------------------------------- 1 | from dnsconfd.configuration import StaticServersOption 2 | 3 | import pytest 4 | 5 | 6 | @pytest.fixture 7 | def instance(): 8 | ins = StaticServersOption("test", "test", []) 9 | ins.lgr.disabled = True 10 | return ins 11 | 12 | 13 | @pytest.mark.parametrize("value, result", [ 14 | ([{"address": "192.168.8.3"}], 15 | True), 16 | ([{"address": "192.168.8"}], 17 | False), 18 | ([{"address": "192.168.8.3"}, 19 | {"address": "192.168.9.3", "protocol": "dns+tls"}], 20 | True), 21 | ([{"address": "192.168.8.3"}, 22 | {"address": "192.168.9.3", "protocol": "garbage"}], 23 | False), 24 | ([{"address": "192.168.8.3"}, 25 | {"address": "192.168.9.3", "protocol": "dns+udp", "routing_domains": ["example.com"]}], 26 | True), 27 | ([{"address": "192.168.8.3"}, 28 | {"address": "192.168.9.3", "protocol": "dns+udp", "routing_domains": [False]}], 29 | False), 30 | ([{"address": "192.168.8.3"}, 31 | {"address": "192.168.9.3", "protocol": "dns+udp", "search_domains": [".", "example.com"]}], 32 | False), 33 | ]) 34 | def test_validate(value, result, instance): 35 | assert instance.validate(value) == result 36 | -------------------------------------------------------------------------------- /dnsconfd/fsm/transitions/transition_implementations.py: -------------------------------------------------------------------------------- 1 | from typing import Callable, Type 2 | import logging 3 | 4 | from dnsconfd.dns_managers import UnboundManager 5 | from dnsconfd.fsm import ContextEvent, ContextState 6 | from dnsconfd.fsm.exit_code_handler import ExitCodeHandler 7 | 8 | 9 | class TransitionImplementations: 10 | 11 | def __init__(self, 12 | config: dict, 13 | dns_mgr: UnboundManager, 14 | exit_code_handler: ExitCodeHandler): 15 | """ Parent class for classes that implement transitions of FSM 16 | 17 | :param config: configuration dictionary 18 | :param dns_mgr: DNS cache manager 19 | :param exit_code_handler: handler of the exit code 20 | """ 21 | self.lgr = logging.getLogger(self.__class__.__name__) 22 | self.config = config 23 | self.dns_mgr = dns_mgr 24 | self.exit_code_handler = exit_code_handler 25 | self.transitions: dict[ 26 | ContextState, 27 | dict[str, 28 | tuple[ContextState, 29 | Callable[[Type["TransitionImplementations"], 30 | ContextEvent], 31 | ContextEvent]]]] = {} 32 | -------------------------------------------------------------------------------- /dnsconfd/dns_managers/dns_manager.py: -------------------------------------------------------------------------------- 1 | from dnsconfd.network_objects import ServerDescription 2 | 3 | 4 | class DnsManager: 5 | """ Parent class of objects that manage DNS caching services """ 6 | 7 | """ Name of service this object manages """ 8 | service_name = None 9 | 10 | def clear_state(self): 11 | """ Revert instance into state after initialization """ 12 | raise NotImplementedError 13 | 14 | def update(self, 15 | zones_to_servers: dict[str, list[ServerDescription]]) -> bool: 16 | """ Update network_objects of a running service 17 | 18 | :param zones_to_servers: dict mapping zones to servers that should 19 | handle them 20 | :type zones_to_servers: dict[str, list[ServerDescription]] 21 | :return: True if update was successful, otherwise False 22 | :rtype: bool 23 | """ 24 | raise NotImplementedError 25 | 26 | def get_status(self) -> dict[str, list[str]]: 27 | """ Get dict representing current network_objects of running service 28 | 29 | :return: dict representing current network_objects of running service 30 | :rtype: dict[str, list[str]] 31 | """ 32 | raise NotImplementedError 33 | -------------------------------------------------------------------------------- /tests/dnsconfd-test-utilities.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM quay.io/fedora/fedora:40 2 | 3 | RUN dnf install -y --setopt=tsflags=nodocs --setopt=install_weak_deps=False dhcp-server \ 4 | dnsmasq which bc openvpn easy-rsa bind bind-utils bind-dnssec-utils openssl iproute iputils radvd vim nftables && dnf -y clean all 5 | 6 | # DHCP PART 7 | COPY dhcpd-common.conf dhcpd-empty.conf /etc/dhcp/ 8 | 9 | COPY radvd.conf /radvd.conf 10 | 11 | # VPN PART 12 | RUN mkdir /etc/openvpn/easy-rsa && cp -rai /usr/share/easy-rsa/3/* /etc/openvpn/easy-rsa/ 13 | RUN cd /etc/openvpn/easy-rsa\ 14 | && ./easyrsa clean-all\ 15 | && EASYRSA_REQ_CN=vpn ./easyrsa --no-pass --batch build-ca\ 16 | && ./easyrsa --batch --no-pass build-server-full vpn\ 17 | && ./easyrsa --batch --no-pass gen-dh 18 | COPY vpn.conf /etc/openvpn/serverudp.conf 19 | 20 | COPY named.conf /etc/named.conf 21 | COPY named2.conf /etc/named2.conf 22 | COPY bind_zones named_certs/my_signed_cert.pem named_certs/my_private_key.pem named_certs/my_signed_cert2.pem named_certs/my_private_key2.pem /etc/named/ 23 | RUN chown named /etc/named/my_signed_cert.pem /etc/named/my_private_key.pem /etc/named/my_signed_cert2.pem /etc/named/my_private_key2.pem 24 | 25 | COPY dhcp_entry.sh vpn_entry.sh dnsmasq_entry.sh bind_entry.sh ratool_entry.sh /usr/bin/ 26 | -------------------------------------------------------------------------------- /dnsconfd/fsm/context_state.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | # states marked with interrupt need to handle UPDATE and STOP events 5 | class ContextState(Enum): 6 | """ State the Dnsconfd FSM can be in """ 7 | STARTING = 1 # interrupt 8 | WAITING_FOR_START_JOB = 2 # interrupt 9 | RUNNING = 4 # interrupt 10 | STOPPING = 5 11 | CONNECTING_DBUS = 7 12 | SUBMITTING_START_JOB = 8 13 | UPDATING_RESOLV_CONF = 10 14 | UPDATING_DNS_MANAGER = 11 15 | SUBMITTING_STOP_JOB = 12 16 | WAITING_STOP_JOB = 13 # interrupt 17 | REVERTING_RESOLV_CONF = 14 18 | WAITING_TO_SUBMIT_STOP_JOB = 15 # interrupt 19 | SUBMITTING_RESTART_JOB = 16 20 | WAITING_RESTART_JOB = 17 # interrupt 21 | REVERT_RESOLV_ON_FAILED_RESTART = 18 22 | CONFIGURING_DNS_MANAGER = 19 23 | REMOVING_ROUTES = 21 24 | SUBSCRIBING_NM_CONNECTIONS = 22 25 | 26 | UNSUBSCRIBE_NM_AND_WAIT = 23 # interrupt 27 | 28 | UNSUBSCRIBE_IMMEDIATE = 24 29 | 30 | CHECK_ALL_CONNECTIONS_UP = 25 31 | WAIT_ALL_CONNECTIONS_UP = 26 # interrupt 32 | 33 | GATHER_CONN_CONFIG = 27 34 | 35 | SUBSCRIBE_IP_CHANGES = 28 36 | CHECK_IP_OBJECTS = 29 37 | WAIT_IP_OBJECTS = 30 # interrupt 38 | 39 | MODIFY_CONNECTIONS = 31 40 | REMOVE_REDUNDANT_ROUTES = 32 41 | 42 | SETTING_RESOLV_CONF = 33 43 | -------------------------------------------------------------------------------- /distribution/dnsconfd-reload.8: -------------------------------------------------------------------------------- 1 | .TH "dnsconfd-reload" "8" "09 Apr 2025" "dnsconfd-1.7.3" "" 2 | 3 | .SH NAME 4 | 5 | dnsconfd-reload - Reload running cache service 6 | 7 | .SH SYNOPSIS 8 | 9 | dnsconfd reload [options] 10 | 11 | .SH DESCRIPTION 12 | 13 | Reload command allows you to reload running cache service. In other words, 14 | configuration will be cleared and pushed again. 15 | 16 | .SH OPTIONS 17 | 18 | .IP "-h, --help" 19 | Show help message and exit 20 | 21 | .SH "EXIT STATUS" 22 | 23 | .IP 0 24 | Everything went as expected. 25 | .IP 1 26 | Error occurred. 27 | .IP 13 28 | Bad arguments. 29 | 30 | .SH ENVIRONMENT 31 | Environment variables have lower priority than command line options but higher 32 | than configuration file. 33 | 34 | .IP DBUS_NAME 35 | DBUS name that dnsconfd should use, default com.redhat.dnsconfd 36 | .IP LOG_LEVEL 37 | Log level of dnsconfd, default INFO 38 | .IP CONFIG_FILE 39 | Path where config file is located, default /etc/dnsconfd.conf 40 | 41 | .SH "REPORTING BUGS" 42 | Please for reporting bugs use Github repository https://github.com/InfrastructureServices/dnsconfd 43 | 44 | .SH "SEE ALSO" 45 | \fB dnsconfd(8)\fP Dnsconfd daemon 46 | \fB dnsconfd-status(8)\fP Check status of dnsconfd 47 | \fB dnsconfd-config(8)\fP Change configuration of host 48 | \fB dnsconfd-update(8)\fP Change Dnsconfd configuration 49 | \fB dnsconfd.conf(5)\fP Dnsconfd configuration file 50 | 51 | .SH COPYRIGHT 52 | 53 | Copyright (c) 2023 Red Hat, Inc. -------------------------------------------------------------------------------- /distribution/dnsconfd-status.8: -------------------------------------------------------------------------------- 1 | .TH "dnsconfd-status" "8" "09 Apr 2025" "dnsconfd-1.7.3" "" 2 | 3 | .SH NAME 4 | 5 | dnsconfd-status - Check status of dnsconfd 6 | 7 | .SH SYNOPSIS 8 | 9 | dnsconfd status [options] 10 | 11 | .SH DESCRIPTION 12 | 13 | Status command allows you to retrieve status of running dnsconfd instance. 14 | 15 | .SH OPTIONS 16 | 17 | .IP "-h, --help" 18 | Show help message and exit 19 | .IP "--json" 20 | Status should be formatted as JSON string 21 | 22 | .SH "EXIT STATUS" 23 | 24 | .IP 0 25 | Everything went as expected. 26 | .IP 1 27 | Error occurred. 28 | .IP 13 29 | Bad arguments. 30 | 31 | .SH ENVIRONMENT 32 | Environment variables have lower priority than command line options but higher 33 | than configuration file. 34 | 35 | .IP DBUS_NAME 36 | DBUS name that dnsconfd should use, default com.redhat.dnsconfd 37 | .IP LOG_LEVEL 38 | Log level of dnsconfd, default INFO 39 | .IP CONFIG_FILE 40 | Path where config file is located, default /etc/dnsconfd.conf 41 | 42 | .SH "REPORTING BUGS" 43 | Please for reporting bugs use Github repository https://github.com/InfrastructureServices/dnsconfd 44 | 45 | .SH "SEE ALSO" 46 | \fB dnsconfd(8)\fP Dnsconfd daemon 47 | \fB dnsconfd-reload(8)\fP Reload running cache service 48 | \fB dnsconfd-config(8)\fP Change configuration of host 49 | \fB dnsconfd-update(8)\fP Change Dnsconfd configuration 50 | \fB dnsconfd.conf(5)\fP Dnsconfd configuration file 51 | 52 | .SH COPYRIGHT 53 | 54 | Copyright (c) 2023 Red Hat, Inc. -------------------------------------------------------------------------------- /tests/dnsconfd.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM scratch 2 | 3 | COPY ./baseroot / 4 | COPY ./*.rpm ./ 5 | RUN dnf install -y --setopt=install_weak_deps=False --setopt=tsflags=nodocs systemd \ 6 | NetworkManager iproute ./*.rpm openvpn NetworkManager-openvpn sssd-client \ 7 | polkit bind-utils bind-dnssec-utils dbus-tools net-tools rsyslog tcpdump procps-ng python3-idna vim crypto-policies-scripts less gdb 8 | 9 | # we will replace the path in code only for testing purposes 10 | # accessing sysfs in the container could be dangerous for the host machine and would require 11 | # running container as privileged 12 | # this may be a bit of a hack but it is safer 13 | RUN sed -i "s#/sys/class/net/#/tmp/is_wireless/#" /usr/lib/python3*/site-packages/dnsconfd/network_objects/interface_configuration.py \ 14 | && echo 'LOG_LEVEL=DEBUG' >> /etc/sysconfig/dnsconfd 15 | 16 | # increase unbound logging 17 | RUN sed -i "s/verbosity.*/verbosity: 5/g" /etc/unbound/unbound.conf 18 | 19 | RUN printf "[main]\ndns=dnsconfd\n[logging]\ndomains=ALL:TRACE\n" > /etc/NetworkManager/conf.d/dnsconfd.conf 20 | # enable dnsconfd 21 | RUN systemctl enable dnsconfd 22 | 23 | # this is neccessary because of https://github.com/systemd/systemd/issues/29860 24 | # first 13 lines do not contain sandboxing options that trigger fail because 25 | # of missing CAP_SYS_ADMIN 26 | RUN head -n 13 /usr/lib/systemd/system/polkit.service > /polkit.tmp; cat /polkit.tmp > /usr/lib/systemd/system/polkit.service 27 | 28 | ENTRYPOINT /usr/sbin/init 29 | -------------------------------------------------------------------------------- /plans/unit.fmf: -------------------------------------------------------------------------------- 1 | summary: Run unit tests 2 | execute: 3 | how: tmt 4 | script: pytest -vv unittests/ 5 | prepare: 6 | - name: packages 7 | order: 4 8 | how: install 9 | package: 10 | - python3-pytest 11 | - python3-pyyaml 12 | - python3-dbus 13 | - python3-gobject-base 14 | - python3-systemd 15 | adjust: 16 | - when: trigger is not defined or trigger == human 17 | provision: 18 | how: virtual 19 | image: fedora-rawhide 20 | - when: distro == centos-stream or distro == rhel 21 | prepare+: 22 | - how: shell 23 | name: enable CRB 24 | order: 1 25 | script: 'dnf config-manager --set-enabled crb || dnf config-manager --set-enabled rhel-CRB || dnf config-manager --set-enabled beaker-CRB' 26 | - when: distro == centos-stream-9 or distro == rhel-9 27 | prepare+: 28 | - how: install 29 | name: install EPEL 30 | order: 2 31 | package: 32 | - https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm 33 | - when: distro == centos-stream-10 or distro == rhel-10 34 | prepare+: 35 | - how: install 36 | name: install EPEL 37 | order: 2 38 | package: 39 | - https://dl.fedoraproject.org/pub/epel/epel-release-latest-10.noarch.rpm 40 | - when: distro == centos-stream or distro == rhel 41 | prepare+: 42 | - how: shell 43 | name: enable EPEL 44 | order: 3 45 | script: 'dnf config-manager --set-enabled epel' 46 | -------------------------------------------------------------------------------- /micro-dnsconfd/arg-parsing.c: -------------------------------------------------------------------------------- 1 | #include "arg-parsing.h" 2 | 3 | #include 4 | 5 | // these two can not be static, because they are already declared in argp.h 6 | const char *argp_program_version = "micro-dnsconfd"; 7 | const char *argp_program_bug_address = ""; 8 | 9 | static char doc[] = "Generator of resolv.conf and unbound configuration, " 10 | "parsing NM global config"; 11 | static char args_doc[] = "[-r ] [-u input; 21 | switch (key) { 22 | case 'r': 23 | arguments->resolvconf = arg; 24 | break; 25 | case 'u': 26 | arguments->unboundconf = arg; 27 | break; 28 | case 'n': 29 | arguments->no_error_code = 1; 30 | break; 31 | case ARGP_KEY_ARG: 32 | return 0; 33 | default: 34 | return ARGP_ERR_UNKNOWN; 35 | } 36 | return 0; 37 | } 38 | 39 | static struct argp argp = {options, parse_opt, args_doc, doc, 0, 0, 0}; 40 | 41 | error_t parse_args(int argc, char *argv[], arguments *args) { 42 | return argp_parse(&argp, argc, argv, 0, 0, args); 43 | } 44 | -------------------------------------------------------------------------------- /tests/dbus-status/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k 3 | . /usr/share/beakerlib/beakerlib.sh || exit 1 4 | 5 | rlJournalStart 6 | rlPhaseStartSetup 7 | rlRun "set -o pipefail" 8 | rlRun "useradd dummy" 0 "Adding dummy user" 9 | rlPhaseEnd 10 | 11 | rlPhaseStartTest 12 | rlRun "dnsconfd config nm_enable" 0 "Installing dnsconfd" 13 | rlServiceStart dnsconfd 14 | rlRun "sudo -u dummy dnsconfd status | grep unbound" 0 "Verifying status of dnsconfd as dummy user" 15 | # we can not simply check for a AVC until chrony issue is fixed 16 | rlRun "sudo -u dummy dbus-send --system --dest=org.freedesktop.resolve1 --print-reply\ 17 | --type=method_call /org/freedesktop/resolve1 \ 18 | org.freedesktop.resolve1.Manager.RevertLink int32:1" 1 "Verify that regular user is not permitted to change DNS setting" 19 | rlRun "ausearch -m avc --start recent | grep dnsconfd" 1 "Check no AVC occured" 20 | rlPhaseEnd 21 | 22 | rlPhaseStartCleanup 23 | rlRun "journalctl -u dnsconfd" 0 "Saving dnsconfd logs" 24 | rlRun "journalctl -u unbound" 0 "Saving unbound logs" 25 | rlRun "ip route" 0 "Saving present routes" 26 | rlServiceRestore dnsconfd 27 | rlFileRestore 28 | rlRun "journalctl -u dnsconfd" 0 "Saving logs" 29 | rlRun "dnsconfd config uninstall" 0 "Uninstalling dnsconfd privileges" 30 | rlRun "userdel dummy" 0 "Removing dummy user" 31 | rlPhaseEnd 32 | rlJournalEnd 33 | -------------------------------------------------------------------------------- /dnsconfd/network_manager.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | 3 | 4 | class NetworkManager: 5 | NM_CONF_D = "/etc/NetworkManager/conf.d" 6 | NM_CONF = NM_CONF_D + "/dnsconfd.conf" 7 | HEADER = "## This file is maintained by " \ 8 | "dnsconfd tool, do not edit by hand!\n" 9 | 10 | @staticmethod 11 | def reload(): 12 | """ Perform reload of Network Manager """ 13 | subprocess.run(["systemctl", "reload", "NetworkManager"], 14 | capture_output=True, 15 | check=True) 16 | 17 | def enable(self) -> bool: 18 | """ Enables dnsconfd in Network Manager. Requires root privileges. """ 19 | try: 20 | with open(self.NM_CONF, "w", encoding="utf-8") as f: 21 | # TODO: have own plugin in NM 22 | f.writelines([self.HEADER, 23 | "[main]\n", 24 | "dns=dnsconfd\n"]) 25 | except OSError as e: 26 | print(f"Unable to configure network manager: {e}") 27 | return False 28 | self.reload() 29 | return True 30 | 31 | def disable(self) -> bool: 32 | """ Disables dnsconfd in Network Manager. Requires root privileges. """ 33 | try: 34 | with open(self.NM_CONF, "w", encoding="utf-8") as f: 35 | f.writelines([self.HEADER]) 36 | except OSError as e: 37 | print(f"Unable to configure network manager: {e}") 38 | return False 39 | self.reload() 40 | return True 41 | -------------------------------------------------------------------------------- /tests/vpn.conf: -------------------------------------------------------------------------------- 1 | port 1194 2 | dev tun 3 | 4 | topology subnet 5 | # Use "local" to set the source address on multi-homed hosts 6 | local 192.168.6.30 7 | 8 | # TLS parms 9 | tls-server 10 | ca /etc/openvpn/easy-rsa/pki/ca.crt 11 | cert /etc/openvpn/easy-rsa/pki/issued/vpn.crt 12 | key /etc/openvpn/easy-rsa/pki/private/vpn.key 13 | dh /etc/openvpn/easy-rsa/pki/dh.pem 14 | 15 | # Tell OpenVPN to be a multi-client udp server 16 | mode server 17 | 18 | server 10.8.0.0 255.255.255.0 19 | 20 | # The server's virtual endpoints 21 | #ifconfig 10.8.0.1 10.8.0.2 22 | 23 | # Pool of /30 subnets to be allocated to clients. 24 | # When a client connects, an --ifconfig command 25 | # will be automatically generated and pushed back to 26 | # the client. 27 | #ifconfig-pool 10.8.0.4 10.8.0.255 28 | 29 | # Push route to client to bind it to our local 30 | # virtual endpoint. 31 | push "route 10.8.0.1 255.255.255.255" 32 | 33 | # Push any routes the client needs to get in 34 | # to the local network. 35 | push "route 192.168.7.0 255.255.255.0" 36 | 37 | # Push DHCP options to Windows clients. 38 | push "dhcp-option DOMAIN vpndomain.com" 39 | push "dhcp-option DNS 192.168.7.2" 40 | 41 | # Client should attempt reconnection on link 42 | # failure. 43 | keepalive 10 60 44 | 45 | # Delete client instances after some period 46 | # of inactivity. 47 | inactive 600 48 | 49 | # Route the --ifconfig pool range into the 50 | # OpenVPN server. 51 | route 10.8.0.0 255.255.255.0 52 | 53 | # Keep TUN devices and keys open across restarts. 54 | persist-tun 55 | persist-key 56 | 57 | verb 4 58 | -------------------------------------------------------------------------------- /unittests/configuration/test_syslog_option.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | from dnsconfd.configuration import SyslogOption 4 | 5 | import pytest 6 | 7 | 8 | @pytest.fixture 9 | def instance(): 10 | ins = SyslogOption("test", 11 | "test", 12 | "whatever") 13 | ins.lgr.disabled = True 14 | return ins 15 | 16 | 17 | @pytest.mark.parametrize("value, result", [ 18 | ("unix:/dev/log", True), 19 | ("udp:localhost:514", True), 20 | ("udp:[::1]:514", True), 21 | ("tcp:127.0.0.1:514", True), 22 | ("tcp:host.example.com:514", True), 23 | ("tcp:host.example.com:", False), 24 | ("garbage", False), 25 | ("unix:", False), 26 | ("tcp::514", False), 27 | ]) 28 | def test_validate(value, result, instance): 29 | assert instance.validate(value) == result 30 | 31 | 32 | @pytest.mark.parametrize("value, result", [ 33 | ("unix:/dev/log", {"path": "/dev/log"}), 34 | ("udp:localhost:514", {"socket_type": socket.SOCK_DGRAM, 35 | "host": "localhost", "port": 514}), 36 | ("udp:[::1]:514", {"socket_type": socket.SOCK_DGRAM, 37 | "host": "::1", "port": 514}), 38 | ("tcp:127.0.0.1:514", {"socket_type": socket.SOCK_STREAM, 39 | "host": "127.0.0.1", "port": 514}), 40 | ("tcp:host.example.com:514", {"socket_type": socket.SOCK_STREAM, 41 | "host": "host.example.com", "port": 514}), 42 | ]) 43 | def test_parse_value(value, result, instance): 44 | assert instance.parse_value(value) == result 45 | -------------------------------------------------------------------------------- /dnsconfd/configuration/option.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | 4 | class Option: 5 | def __init__(self, 6 | name: str, 7 | desc: str, 8 | default, 9 | in_file: bool = True, 10 | in_args: bool = True, 11 | in_env: bool = True, 12 | validation=None): 13 | """ Dnsconfd configuration option 14 | 15 | :param name: name of configuration option 16 | :param desc: description of configuration option 17 | :param default: default value 18 | :param in_file: can be entered in configuration file 19 | :param in_args: can be entered in cmdline arguments 20 | :param in_env: can be entered through environment variables 21 | :param validation: data necessary for validation 22 | """ 23 | self.name = name 24 | self.desc = f"{desc}, Default is {default}" 25 | self.default = default 26 | self.in_file = in_file 27 | self.in_args = in_args 28 | self.in_env = in_env 29 | if not self.in_file and not self.in_env and not self.in_args: 30 | raise ValueError("Option with no allowed input") 31 | self.lgr = logging.getLogger(self.__class__.__name__) 32 | self.validation = validation 33 | 34 | def validate(self, value) -> bool: 35 | """ Validate that the value is allowed 36 | 37 | :param value: Value that should be validated 38 | :return: True if value is correct, otherwise False 39 | :rtype: bool 40 | """ 41 | return True 42 | -------------------------------------------------------------------------------- /tests/start/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k 3 | . /usr/share/beakerlib/beakerlib.sh || exit 1 4 | 5 | rlJournalStart 6 | rlPhaseStartSetup 7 | rlRun "set -o pipefail" 8 | rlFileBackup /etc/dnsconfd.conf 9 | rlPhaseEnd 10 | 11 | rlPhaseStartTest 12 | rlRun "dnsconfd config nm_enable" 0 "Installing dnsconfd" 13 | rlServiceStart dnsconfd 14 | sleep 2 15 | rlRun "dnsconfd status | grep unbound" 0 "Verifying status of dnsconfd" 16 | # test also new api 17 | rlRun "echo 'api_choice: dnsconfd' >> /etc/dnsconfd.conf" 18 | rlServiceStart dnsconfd 19 | rlRun "dnsconfd update --json '[{\"address\":\"192.168.6.3\", \"interface\": \"eth0\"}]'" 20 | sleep 2 21 | rlRun "dnsconfd status | grep unbound" 0 "Verifying status of dnsconfd" 22 | # we can not simply check for a AVC until chrony issue is fixed 23 | rlRun "ausearch -m avc --start recent | grep dnsconfd" 1 "Check no AVC occured" 24 | rlRun "ls -Z /bin/dnsconfd | grep dnsconfd_exec_t" 0 "Verify that dnsconfd executable has right context" 25 | rlPhaseEnd 26 | 27 | rlPhaseStartCleanup 28 | rlRun "journalctl -u dnsconfd" 0 "Saving dnsconfd logs" 29 | rlRun "journalctl -u unbound" 0 "Saving unbound logs" 30 | rlRun "ip route" 0 "Saving present routes" 31 | rlServiceRestore dnsconfd 32 | rlFileRestore 33 | rlRun "journalctl -u dnsconfd" 0 "Saving logs" 34 | rlRun "dnsconfd config uninstall" 0 "Uninstalling dnsconfd privileges" 35 | rlPhaseEnd 36 | rlJournalEnd 37 | -------------------------------------------------------------------------------- /tests/named_certs/my_cert_req.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIElzCCAn8CAQAwUjELMAkGA1UEBhMCQ1oxFTATBgNVBAcMDERlZmF1bHQgQ2l0 3 | eTEcMBoGA1UECgwTRGVmYXVsdCBDb21wYW55IEx0ZDEOMAwGA1UEAwwFbmFtZWQw 4 | ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC1C61hmqkU9Y1twFCf5qFv 5 | yu8ju7KSruyo42st+9a8jlQN5lq6VSunzeOuLCNTfaREtJkMFgOrUoJIgIKNbecu 6 | ZSxyOAQXNBtsbkGAMBuDZwGZHEEpghuxrXEpVm2gRSMJsU7cZP/bPDISFFQAlW5/ 7 | SflmJ/oKh0SckDyR4G4Iir/jNeyFdry8yMD1cAN09adBkfj13gGXHMENNZHEWyj1 8 | JDMI3zWsR9rmn+dLw/RJBm/TMoYr24hehwuZTrw7GO+ElgARgm990yOlNNcliWUo 9 | B02tBrLnoWVIVsigV2+4kqSiNUOU5O7yAbvuGWBLejywPRPq91Kzyff+DUvnlu4b 10 | fsq5IRdb2TLuUKC2CbFTDAg1F2J8D2SpNH2B+/WVXH7nQj9E8adOf/JFCa3rXHqo 11 | i/x7EffsmRuNxkmVOKhExBhM2sy6JIz4znTUgowD+TsmWRHC2Q571vQa9onNUP48 12 | FRwBhG1NVzv2hHHaEPqDMEQgk8gHpNVLhLO8QVXJfxUnLPobWxRnLZKZ0J65chTR 13 | 4UW6uP/E3YRPH8xejJgWL2RSIJvicEQ7XDbKlZuIVz811XQmfCUDmwUG6Xwuahw6 14 | w3ZBxYCl4hHXwvVqyyxFuQPDxHJi22dAl43Bs7yyZzDM0Ow1kBbLDkmJubblJlGn 15 | APNo1MSHYjLtOFKGanYTywIDAQABoAAwDQYJKoZIhvcNAQELBQADggIBALHNI70e 16 | cIU26lN9bfJ1Sc3TDuTIOVZOyhOmGgS54rU8Jczvgk2UUmJWTX8Ad17bRyPe+C6u 17 | GhxN5C6+GHrSyCTSyxh5OXEgu1TxxGDEpPdHNayVglFhb9gyeeQBDezvBMbgtzeH 18 | zpfeYV/+5BR7kQNr2k0FlnAoOYBYxSjY2EFssAbbs+bcvHP1cWslIs0CB51iNfnX 19 | /tJ84somnNk5GXWlJ+GkO+xoqNE2JJNJ30vWK+BrQEEx0+Jpa4DNRukS/kMF1GwP 20 | ef4ILabUdin7Y3nDDua7wsrVGta7beSmwANHKNUUJHQmNOyZZI9G8u8vsPohNs4s 21 | pwqfzySxAs+RfjGvfi+bUBlYD+okjSKcQFB0h6YB6gHJnP4pAox3pJ4Mk7DnVXEY 22 | pVZ7yB+Wgd2YXqFh9yYOZ7FnRWa6PZE2nyXRh0NA2o1Ksi3q0FoWNnLaRsHLftW5 23 | dB3vSAYn3UumYyUrNhqC5cjTGWz/E6i/msVVMBkwGLmegeukvsdh/udt9G8jILmu 24 | PhhqI6J9nEHU1GB5GJCgpCZTmWYsY8FV2bArF/4wWaItWjTCsoZAIa3dqnWpFMOu 25 | 7tZsPBsMvUWENFiJBoZlRLSr6dqDLLz+NpjGHC70yUncMG5bdukUgy4oD+Wl+1d8 26 | yZ+Om61aIb1H1Q/0O+WO+AXaDIS7+2y2i0rx 27 | -----END CERTIFICATE REQUEST----- 28 | -------------------------------------------------------------------------------- /micro-dnsconfd/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(micro-dnsconfd LANGUAGES C) 3 | enable_testing() 4 | 5 | find_package(PkgConfig REQUIRED) 6 | 7 | pkg_check_modules(glib-2.0 REQUIRED IMPORTED_TARGET glib-2.0) 8 | pkg_check_modules(gio-2.0 IMPORTED_TARGET REQUIRED gio-2.0) 9 | pkg_check_modules(libcurl REQUIRED IMPORTED_TARGET libcurl) 10 | pkg_check_modules(check REQUIRED IMPORTED_TARGET check) 11 | 12 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall") 13 | 14 | add_executable( 15 | micro-dnsconfd 16 | micro-dnsconfd.c 17 | uri-parsing.c 18 | uri-parsing.h 19 | dbus-handling.c 20 | dbus-handling.h 21 | arg-parsing.c 22 | arg-parsing.h 23 | output-handling.c 24 | output-handling.h 25 | nm-config-parsing.c 26 | nm-config-parsing.h 27 | file-utilities.c 28 | file-utilities.h 29 | ) 30 | target_link_libraries(micro-dnsconfd PUBLIC PkgConfig::glib-2.0 PkgConfig::gio-2.0 PkgConfig::libcurl) 31 | target_include_directories(micro-dnsconfd PUBLIC PkgConfig::glib-2.0 PkgConfig::gio-2.0 PkgConfig::libcurl) 32 | 33 | add_executable( 34 | runtests 35 | tests/runtests.c 36 | tests/test-uri-parsing.c 37 | tests/test-uri-parsing.h 38 | tests/test-nm-config-parsing.c 39 | tests/test-nm-config-parsing.h 40 | uri-parsing.c 41 | uri-parsing.h 42 | dbus-handling.c 43 | dbus-handling.h 44 | arg-parsing.c 45 | arg-parsing.h 46 | output-handling.c 47 | output-handling.h 48 | nm-config-parsing.c 49 | nm-config-parsing.h 50 | file-utilities.c 51 | file-utilities.h 52 | ) 53 | target_link_libraries(runtests PkgConfig::check PkgConfig::gio-2.0 PkgConfig::libcurl) 54 | target_include_directories(runtests PUBLIC PkgConfig::check PkgConfig::gio-2.0 PkgConfig::libcurl ${CMAKE_SOURCE_DIR}) 55 | add_test(NAME runtests 56 | COMMAND runtests) 57 | 58 | install(TARGETS micro-dnsconfd RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) 59 | -------------------------------------------------------------------------------- /tests/bind_zones/Kcom.+008+23814.private: -------------------------------------------------------------------------------- 1 | Private-key-format: v1.3 2 | Algorithm: 8 (RSASHA256) 3 | Modulus: zfiFMf5PgSuAKZck3sdTs1hhQDXiM27vZn23GWfGWKbkbWkIucZOymTcBMwmc6UqHfz/SnXANN2ya4HPt51jX4caRy2OouMIUvci7/SfHGsVBcjfPCeHq1O0TfweHTZ9P4PSSx6aUiAljouYouEInsC5lc1M4oploXtWEPNg1a3zpnnML6J8KxT4Zp8iUy3CkZ3aO9YL8Ly9tcQyP+eMEiBp/K/jsSLhqOcS7mK5IqK1gMSFrMo3GC08Z7MfTsDKxn5ffv3aE+0D2b7yerCl7Kul4ZvF4XgXGRjSR+LcApU30f7LJozwZAd7gGE2EPoMQi0nnarPd2n89VWNyi6gKQ== 4 | PublicExponent: AQAB 5 | PrivateExponent: Aa2aIzaYg1DytT609zzd7havddMX5dX2wh8Ogk4wb+Q4iqTUjv6XltSkdMRiNfwVDY5pmOZq85tQovQurbGs9Q2AHa9DC7QdwHRLmZ4kpjn/9Lk8Crd35ox9lMrpMWZ9CyrkfZtxGS/Hx+NUBz6zX+dqKQHq/pJaAotDVSBwgWkqybrPkZyJuVApzcOSSPQQ18BCHw5VrFYC+nTaXcEvO94+thFDl6+7Z93jGSKSyBPJ36SDUEef8YuYSk7tjGn4qiUnSA6h9xHpGOQWXBZ6mJ8Gr4OAPIFJMIBNNdIuHCXMpSAHJrlQ1qveyvaK/9VXcOb9shem5fVnIub/948eoQ== 6 | Prime1: 9bRwcEnURu4NGjCXx9+1JOIEOoUm7sLJP95eeeOOhkzpslJF7hm1KpdUFj8RKHXMRqXKqBOcZFjSiD8wNyXEqC1RBf+Mn+BF+o5SJZ39M/MzusXYSnc/PY/JO5MvLKUZuWW+C5c8nohTDeK6d8g3FtzHE4GrwAp7GYZPnS0ZkiE= 7 | Prime2: 1pnfWEyYArBo4NKqQkmXhIDdyQjJ+PXErPEHPGoRO3EzzYKXq0Mr6HGATkdRcf+v14F5smNzmCJwk7kEbIA7rtaNc8QVQ7GBM0z5frrHNrdEbnSXCL8XiRKne/VWuiKdaeIXgQMiQ4Vs+BfyZIddU3LlQzG0O4A0vbEAISDi3Qk= 8 | Exponent1: wnVYN8Z2ttxYik3DEnE+0D4A0r/nHDgVRvMbGqS6fBgLLRJoPhUiiN7TsfegAMGaNp+oUHWU5OZXWXWJF1xQ1DlpUrH5/d5mA/L3mMX9S0xDuKI0mFrgNjzCKuBGCbNxNIYNbub3FxEVinvS0FIpJ3L8K7gI0ih5XK4r/F1hS4E= 9 | Exponent2: g2s7sVFGje8GaxfXmDyFA2n/aAtv1Hx9cwMv0TmLUAGlHadpxkGec/x9/HIEWHGid7Ecm7f3pCUDGBPnt6JX6lwNx+U+uHPNkWMELy2mrcVRrOrNS1fqy9CWrHy0Hczw5VTF3AXVR9A/yTaxBAs5hc8Iwzt/CikbI0dvstn21DE= 10 | Coefficient: xpKBwrbUEYUe9xq1EfpZOiH3Tsdrutxj1c3YvcX47gFpRnhx9v1bkPhZTurTH30hQ0qfCfcI3zBq+GqP5ILLsjXZYKm6ugVEsPmjmjohniV1mWrySG7Us2+JtoO/lj6uRncnHQIwHDEHKO6j01YH1+//TFnqUcDkNnozCwF1YMQ= 11 | Created: 20241213124027 12 | Publish: 20241213124027 13 | Activate: 20241213124027 14 | -------------------------------------------------------------------------------- /tests/named_certs/ca_private_key2.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDI/n3NFkphXIn/ 3 | e6L6eKeaP4NvU96Ic/wALpMwDE6tW46sod9kAWxNYDKZpoXo7s0SFPvLMSXps0oC 4 | R/XClqvhusbC786RFMctlZslX35cdyrFfKX1uHS9ak8vPYZ1+6fExyhNqAIOWPjn 5 | opw+Dq4toAgO+I0/XrbpOqU9/7fGaeNsEDT0KTVMtYP/7EWbVd40llLRypEBXHbh 6 | HBpQB8PyuDjaQRYg0qgGLeFimWeRb+2rJWx4FFkk+7qSlEtefkCKONm6NFqReQid 7 | gZiXPzsW/tgAImreCgvJYic6rHzXUVsyiZZweJSfJDsTbr+QF43ePoQs/eojG43/ 8 | 1hTMDnAJAgMBAAECggEADUjAsMrd3KR8nG2j/nD2BtxWyAdfiF4+FBb/9GeD1bJc 9 | 8iz6skXjzhNjFMOsSxJpbF4FrE7Rxinq5M6zwAosTw2EsIKgAPfCGFGwgN5YYC0i 10 | Hw5Xe6+Wy6QYmrMyzV52HqvZDpThmegof0rAj9txiKNwlOi5kSwl47FUFY5uq4ba 11 | /q7IH5pxG0bDmzMFKTzr5TDN1djBvxF+x+X87CyxaZER3W01CSfHCG65ZkspECZt 12 | EeuZoaIpqMH0Wyfj0FDiTRYiOYtX5BY4kMozNn/yAN7QikF7n9IS0dpodFiOG6KX 13 | 2884fl1JgODhg8++b6ZiaQ4XkLO+BkSaUYwhNq3JQQKBgQD3vMHyhDBEPKOHwQll 14 | XTcr10XTtsuGLzGulZj0fXnG6/XwuvnhFkyvps4m/hWnMGIt93P37+8RRsRcW3sW 15 | 5wIn3p0AwfXoWLugQZZuC7xjUVtgFhnKYw/1uByLy4CmvJTNLQb4PsMxb89Cw9Iw 16 | DJ/bFDAH1T5a1n6KUvdehvJWOQKBgQDPsqDszjTjXibL0FQfnT1VTUk5tfxRbbWI 17 | eJ7oHEcICJeVqgQCscNlQWThQEgYt9h0l6s3hlrtkKNmTkB63+BqO5W93GckRTQp 18 | +fEEYgMfl32eccoap9pmNsnFO97FKRYfxcstXRKg6DWm+bEN6MdkztBr7LJOutS2 19 | erILiSpoUQKBgE+mmbjudVJLKMzJ7MpxWP64fRPfzrn6zH90S7Q374JcdTuL8jFD 20 | aS6Ec/2nbbDOZpKe3+NUeknUted35jBr346QDWyj7/tfJBwXWlVRYqWQD8/p6yre 21 | BNCc/FiZ+mghc7owAvCnxTxM1ZeCvD6EoJTgfbzW+/BazF6O5Ee5HYtJAoGAcMJN 22 | 08JvvDDVZzmHMlKvhawb4RUIEz04nQq/WsxfU+E2Sq6u1rejmUlTd2bqvWCyRzpA 23 | Xji3DNrFmzlIkG0S7RnERftuk6Zul4t2aia8A16/eFHWo3oVfACqskW6v9d6h21e 24 | zRYGkwz+c9SDZ0XFWtldFfq/IzcTXK5oExM4zsECgYEAoVC6xGCPWEo78dIJZhzu 25 | Gp23DE100qqwjTilsdkHRumNgcgK4jVVvZHU+qQRVq9af3ulEAt+/v1oM3EmDR45 26 | Kdk5vupw5ugqbi0fqIQYVr5awp6w7MlgSrLfqfvmJ5/n8tkxokzVQaUyswbPfz+E 27 | yTb/PSau2zyWkg/RNhS5MxM= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /tests/named_certs/my_private_key2.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCvRqTTf+aXv4kV 3 | 5fseNWzU41wRwdw7TZihW2Bwf+UZHNPoGR5Yy9mz++C4W7izwGIU35oGTrSZopML 4 | JGuSBWYN/TrUM1K6t/PiyGmT1laCxdI17KBzekjYzHMoT+YvdD9IlXAQ4sJev14/ 5 | sT9Z6MGkYIYwF2rPj3SvnLpUhQ4I1dCoF/9GaarIkfoY1P/LO3s9trOhxnmnjvUk 6 | AMjBDJ3Gwd7LnTw4OCpFLkwvAgk+vmyRG9beSyo2FfUQZvHJeY8C9uMOOd14MvqE 7 | I+3xsDil3dEZ1YEoqo2bPIT6Llpignp80Lti9h24ajAsLL8i/P1ULN5lLNVQGplC 8 | yc3vLuD3AgMBAAECggEACcuSYYl3ywo2sIUaPA1zSBBusEVbt+q1uWrAYHkdRgKA 9 | 6ysgMYku4OqWG+dwUodRU+ZNFsYmPKHDwu8lndL0aZq5w2sc1/d4xzc5AzyKuCMz 10 | BLV1IA747Di8xMd2TzeZY8aKLT9m6mGadEfFCRLDY5rLVPuyCehz9m51UUzgRGkK 11 | 45DcnIHn/nnJhGaNuz/1ZV2YP2lgfvPWq3WZRNtDaY9ao0uwcGWOZ5AN9Oyo0QD7 12 | 8QSqJAdCU1eY4GykbDxGtlUdn+/8t7FOISIzZQj3c4nqsfJf7equ8CaBniAPBFy1 13 | 90wv8BtkHwnxgeNuW7A5PskS0Q8KKc6qbUxr6bjC9QKBgQDUDshR1kssQKeDE3FW 14 | ETMrHZI14UNV4fVj08ZMhICh0QM3aEPS8/cor5JLVE+yaMFny9xwq+lATWdaLNVf 15 | t6IqBtudiacECl8WCnsUhHfKWdoSk4dUPlfqbIi7813GliRg+t3YWzRg3BW5K7JS 16 | rIXhH22v09bYOfOI6gA1O8mP2wKBgQDTmKolxp2+JWAjVyogxquwPz9k1UNdWC/N 17 | 0usQzph6IzHL3TpTRx68PNef6GNxYrTIhMJ7JxDpn0uChzKXJVQzR62JCQWTTyQc 18 | yDOPJNnlMUDIkIFrR1BOVp4iGhgbi4WIrd5j75WL5vwcbSNrOy+244nXx9TEcfmd 19 | MWkob2h8FQKBgGXqKNoz/HLrK9ayHHE52Paqwp9EgQEglLgCirYxpESg2EPjx1z2 20 | RV33a37qqVbcQ79n2a0I4hQ2XyqWi4HyFmzOWPQQuQUXGvXT2a1VsOC+aDEvWAXj 21 | 5IrU2K5D21jaxecaCk62HqlCfOo+lvhm0/0LBsNPM10+FM5DcBAliMyrAoGABFYJ 22 | jpKeYuojKTY9D8Tiec8h/m/8XGpVOHONC6AgMciM2a+j5Vb8w0C/7m/1sbojGETY 23 | M2vehdsU0gzxNXW3XwGmBbvgmF8zzz8vB0zrBi5XNIT5kfg5JhHSVcKRIedfCij9 24 | +LBNMTu/iNmXszfYR3gsN/bJXmkzg0wi6og17O0CgYEAi3cZt2o8h2+kivR1lUng 25 | eedIjiV/5DxStZZNVpXgjOojQgqK+HRy3EKfokXUs4p2M1CXS+DoxsPxZz3dGyDi 26 | qDwlUljOEazH7Gcy/Aa56pMYiyY5nPxCcyZd0i+vV28Rg49Wu9YLwD8hR+tpGRtx 27 | xUJ6w/TqRkTSKNICRcbjJ6c= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /tests/bind_zones/Kexample.com.+008+42430.private: -------------------------------------------------------------------------------- 1 | Private-key-format: v1.3 2 | Algorithm: 8 (RSASHA256) 3 | Modulus: yWHtJOc2iOgZA4Ea9X7pAtWMAtMHGcNRPh4s8cgpo0siH1rzOEUdZsjqrZZU6KFveLyJxW38hExGAMWeZEemQvqiHkaauE+818cDrakROqp6t/QmvRr1ue9T3k3Gg9HTFcBJ8acczkyxhG35mZecBiuDNWE0usRq04xBJt3zni63I51FOB4mYZBmMaHDVQTt4RO4/eqfsdcueGricpUNfQbljKeB8bSCoJJA5mlfIKkcT7MgaBntVgiZl11umtoMgz3VKhzDR0X14vHBUL7Xm8OUiKEtj9xeZZP9FqdxkOxygHcraLaSA245xgujRU1GLFxo97uHghU2G8JV+hN/zw== 4 | PublicExponent: AQAB 5 | PrivateExponent: BgKqNUPBWOy0cmpUB6e2BKOi/iKWP6qYriXwaXbz5y/C4PSx9af6bKrqdivadOb8kLnv0rippLkyDavYQl3xFGaumAC7dWzL0hTag0Bch0e3Se47icFYPChsdGIV3rFQf4Gxs0itj2qykaVGodLokTaTP/Caxkg+d/njp+lP8BSfNbIwlpuMnYVkQqSl74ojluoYHeXEe3ZkMRymj7+bHxCNU8AroSGdTSpKN6WwpP+H1l60Xp08W0cE1vcoQHf+LfzKY2ekZzXl2fNaKrqa80W43+dgxl108rb6BAve+2KZCG6WrKBVKFL/cm3qK8VQXif5WbXlsRxAJgbJi283IQ== 6 | Prime1: /u9qkmY1qWxXvOemQ21MH7mnxD7QtDuTKeVvd3sOkqSoG/aMv1ZeIzs4gtM09+HYcHhwaSxtbX4g6BzuO7/vfuH7suYoYPzB0/JWlfSMRf0bcy3YRNuasq00VjhKt+BBYkein5Nx7EWkOjaCCITjWQyUe9q5naOLQEB8Y8tZOAM= 7 | Prime2: yjlAAtBR0Rqm4+sbW8IE1Exe/rHERmSdD6INyJ/QcZiLPDJwsrsb8Z3xpLFRrp2MgS/tBhyTgVjFpjmEw+sc/OFDIbdi3wnShW2Ruw4XplCQjYKJ/4LA+bOr/WB4mVRSiMIKleH2aO1op2xInBoArl8U8qbKf7mjcq3d0nsPzUU= 8 | Exponent1: 1ws5yHhzN5DuiaiV9TaTCgffXojmH8JJJwQkfJLO/h/qtnvIyfWevvVLe/+RJK/blTPjDrStMbk9JM6SntAOw+b4HDZNRVKwZYp8Q03frYINz6CSV7Mu0R2NklU1odmHDdIDebw0UuuD1p74HRuLcyhLcBZWkITOB8rdooh7n+U= 9 | Exponent2: eVCnCgkXTC6E+C5PF1jptMKsKndSnDg30O0S/8yAK+Wrgc1wtohxVx29nWOS8QIrDEVIGGaERxCOYg4Xi8E8fqhUsaFmew9VcB4vUtw9a9ThI0OwrcwvIJ2dDEAXmURwzwI5f3kzbfce1XGsjZk711/LHVbaHI2tdFrBvEd/T1E= 10 | Coefficient: 1k42Od04g/6ZD0/XdmzRYJVMR+wMm7xJ0UjBsBXQhYEFtBm6+5hQj7aBzixhXZaUs7R0WxEutE7fqwnXBVBvOb6ZQjnq5PEHqtIDP7gqkNFe6lM19z/+9yIDE51/BQNWzY47qFhKfHpDkxHyw7UV8tm/avLyWqUXI7On6W1taTo= 11 | Created: 20241213123807 12 | Publish: 20241213123807 13 | Activate: 20241213123807 14 | -------------------------------------------------------------------------------- /distribution/dnsconfd-config.8: -------------------------------------------------------------------------------- 1 | .TH "dnsconfd-config" "8" "09 Apr 2025" "dnsconfd-1.7.3" "" 2 | 3 | .SH NAME 4 | 5 | dnsconfd-config - Change configuration of host 6 | 7 | .SH SYNOPSIS 8 | 9 | dnsconfd config [options] 10 | 11 | .SH DESCRIPTION 12 | 13 | Config command allows you to change configuration of service or host. 14 | 15 | .SH COMMANDS 16 | 17 | .IP nm_enable 18 | Config network manager to use dnsconfd 19 | .IP nm_disable 20 | Config network manager to not use dnsconfd 21 | .IP take_resolvconf 22 | Change ownership of resolv conf, so dnsconfd does not need root privileges 23 | .IP return_resolvconf 24 | Return ownership of resolv conf, so root is again the owner 25 | .IP install 26 | Perform all installation steps 27 | .IP uninstall 28 | Perform all uninstallation steps 29 | 30 | .SH OPTIONS 31 | 32 | .IP "-h, --help" 33 | Show help message and exit 34 | 35 | .SH "EXIT STATUS" 36 | 37 | .IP 0 38 | Everything went as expected. 39 | .IP 1 40 | Error occurred. 41 | .IP 13 42 | Bad arguments. 43 | 44 | .SH ENVIRONMENT 45 | Environment variables have lower priority than command line options but higher 46 | than configuration file. 47 | 48 | .IP DBUS_NAME 49 | DBUS name that dnsconfd should use, default org.freedesktop.resolve1 50 | .IP LOG_LEVEL 51 | Log level of dnsconfd, default INFO 52 | .IP CONFIG_FILE 53 | Path where config file is located, default /etc/dnsconfd.conf 54 | 55 | .SH "REPORTING BUGS" 56 | Please for reporting bugs use Github repository https://github.com/InfrastructureServices/dnsconfd 57 | 58 | .SH "SEE ALSO" 59 | \fB dnsconfd(8)\fP Dnsconfd daemon 60 | \fB dnsconfd-reload(8)\fP Reload running cache service 61 | \fB dnsconfd-status(8)\fP Check status of dnsconfd 62 | \fB dnsconfd-update(8)\fP Change Dnsconfd configuration 63 | \fB dnsconfd.conf(5)\fP Dnsconfd configuration file 64 | 65 | .SH COPYRIGHT 66 | 67 | Copyright (c) 2023 Red Hat, Inc. -------------------------------------------------------------------------------- /tests/named_certs/my_signed_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFKDCCAxACFFjpFbgHpaVv7+Xk4py+2I9Z2uT3MA0GCSqGSIb3DQEBCwUAME8x 3 | CzAJBgNVBAYTAkNaMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0Rl 4 | ZmF1bHQgQ29tcGFueSBMdGQxCzAJBgNVBAMMAmNhMB4XDTI0MDUyMTA3NDY0OFoX 5 | DTM0MDUxOTA3NDY0OFowUjELMAkGA1UEBhMCQ1oxFTATBgNVBAcMDERlZmF1bHQg 6 | Q2l0eTEcMBoGA1UECgwTRGVmYXVsdCBDb21wYW55IEx0ZDEOMAwGA1UEAwwFbmFt 7 | ZWQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC1C61hmqkU9Y1twFCf 8 | 5qFvyu8ju7KSruyo42st+9a8jlQN5lq6VSunzeOuLCNTfaREtJkMFgOrUoJIgIKN 9 | becuZSxyOAQXNBtsbkGAMBuDZwGZHEEpghuxrXEpVm2gRSMJsU7cZP/bPDISFFQA 10 | lW5/SflmJ/oKh0SckDyR4G4Iir/jNeyFdry8yMD1cAN09adBkfj13gGXHMENNZHE 11 | Wyj1JDMI3zWsR9rmn+dLw/RJBm/TMoYr24hehwuZTrw7GO+ElgARgm990yOlNNcl 12 | iWUoB02tBrLnoWVIVsigV2+4kqSiNUOU5O7yAbvuGWBLejywPRPq91Kzyff+DUvn 13 | lu4bfsq5IRdb2TLuUKC2CbFTDAg1F2J8D2SpNH2B+/WVXH7nQj9E8adOf/JFCa3r 14 | XHqoi/x7EffsmRuNxkmVOKhExBhM2sy6JIz4znTUgowD+TsmWRHC2Q571vQa9onN 15 | UP48FRwBhG1NVzv2hHHaEPqDMEQgk8gHpNVLhLO8QVXJfxUnLPobWxRnLZKZ0J65 16 | chTR4UW6uP/E3YRPH8xejJgWL2RSIJvicEQ7XDbKlZuIVz811XQmfCUDmwUG6Xwu 17 | ahw6w3ZBxYCl4hHXwvVqyyxFuQPDxHJi22dAl43Bs7yyZzDM0Ow1kBbLDkmJubbl 18 | JlGnAPNo1MSHYjLtOFKGanYTywIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQBOluwC 19 | fMFl+Lmik8hXg/3CFBQPAkxU0NojJj9fIpPfxlneKi9xYEvkZzcnYDzx24lkfBth 20 | xzbGHPt9Q2ax9htaTthzIcl+71ukkEgiGCKohIlfUAW37ZmWPwX+UzWL2CFyqY+5 21 | IGU1+Zk4p446aAcsX5pbGvnWV0vFQtva4wtD24gS0//47MUjueB+R0RicOUy7EGB 22 | MXadP92PvzjSiifPhUKSz5ys31AttbbDlAsGXI2IrV2vhnUR5s5I9mTyTfJnPUVt 23 | 0n34csRFalwg7PaGf5grVq+A/naQ+ayyi/3pyzLqZh+bE9nMgr55FgWAmKo08I9W 24 | yJJ+aTa+j2qXaREBmU9CFMavwXRm+5nXfV8gG4WcIQ/1YIHTjyln4Qpz5J6G/1xF 25 | hIwwQd6l57IJD20lYFBdJnOYhNE9mR/e8j053MTmszkNBpAuBv6nvFaRQKC6SQRk 26 | 4N484r6xLFLCTxdukaNJ6YiNY51GkkIw97wq63ZYkHNutIyc/TJExMMmldi0VEr9 27 | fJt6TYvpI7+1zIZC+LhSG/GNXNMkjWXutwzoCSjgQqe5mGshm8JgJOIUuFUgCU2f 28 | XnzooDsWyLQZzFcXFazu56tN7bFUjbGxoU7YmBXe7auMj500cZhI1wRQWMC8H7Rh 29 | uKWMC4SbJ025Sz+rtURi9+XmQYKGOW97F7Bawg== 30 | -----END CERTIFICATE----- 31 | -------------------------------------------------------------------------------- /micro-dnsconfd/micro-dnsconfd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "arg-parsing.h" 8 | #include "dbus-handling.h" 9 | #include "file-utilities.h" 10 | #include "nm-config-parsing.h" 11 | #include "output-handling.h" 12 | 13 | int main(int argc, char *argv[]) { 14 | arguments args = { 15 | .resolvconf = NULL, .unboundconf = NULL, .no_error_code = 0}; 16 | // dictionary of NetworkManager global options 17 | GVariantDict *glob_dict; 18 | GString *resolv_conf_string; 19 | GString *unbound_conf_string; 20 | char output_rc = 0; 21 | const char *fallback_ca; 22 | 23 | if (parse_args(argc, argv, &args) != 0) { 24 | return args.no_error_code ? 0 : 1; 25 | } 26 | 27 | if (!(glob_dict = get_glob_dict())) { 28 | return args.no_error_code ? 0 : 1; 29 | } 30 | 31 | fallback_ca = get_best_ca_bundle(); 32 | 33 | if (!(unbound_conf_string = 34 | get_unbound_conf_string(glob_dict, fallback_ca, stderr))) { 35 | g_variant_dict_unref(glob_dict); 36 | return args.no_error_code ? 0 : 1; 37 | } 38 | 39 | resolv_conf_string = get_resolv_conf_string(glob_dict, stderr); 40 | g_variant_dict_unref(glob_dict); 41 | 42 | if (!resolv_conf_string) { 43 | g_string_free(unbound_conf_string, 1); 44 | return args.no_error_code ? 0 : 1; 45 | } 46 | 47 | output_rc = handle_output(args.unboundconf, unbound_conf_string); 48 | g_string_free(unbound_conf_string, 1); 49 | 50 | if (output_rc) { 51 | g_string_free(resolv_conf_string, 1); 52 | return args.no_error_code ? 0 : 1; 53 | } 54 | 55 | /// if both files are going to stdout then we need to divide them somehow 56 | if (!args.resolvconf && !args.unboundconf) { 57 | fprintf(stdout, "###\n"); 58 | } 59 | 60 | output_rc = handle_output(args.resolvconf, resolv_conf_string); 61 | g_string_free(resolv_conf_string, 1); 62 | 63 | return args.no_error_code ? 0 : output_rc; 64 | } 65 | -------------------------------------------------------------------------------- /tests/syslog_logging/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k 3 | . /usr/share/beakerlib/beakerlib.sh || exit 1 4 | DBUS_NAME=org.freedesktop.resolve1 5 | 6 | rlJournalStart 7 | rlPhaseStartSetup 8 | rlRun "tmp=\$(mktemp -d)" 0 "Create tmp directory" 9 | rlRun "cp ./rsyslog.conf $tmp/" 10 | rlFileBackup /etc/rsyslog.conf 11 | rlRun "pushd $tmp" 12 | rlRun "set -o pipefail" 13 | rlPhaseEnd 14 | 15 | rlPhaseStartTest 16 | rlRun "dnsconfd config nm_enable" 0 "Installing dnsconfd" 17 | rlServiceStop rsyslog 18 | CUR_TIME=$(date +%T) 19 | # now we will test syslog logging 20 | rlRun "cp rsyslog.conf /etc/rsyslog.conf" 21 | rlServiceStart rsyslog 22 | rlRun "printf 'syslog_log: unix:/dev/newlog\n' >> /etc/dnsconfd.conf" 0 "Enabling syslog logging" 23 | rlServiceStart dnsconfd 24 | sleep 3 25 | rlRun "journalctl --since \"$CUR_TIME\" | grep 'ContextState.RUNNING'" 0 "verify logs are indeed in syslog" 26 | rlServiceStop rsyslog 27 | CUR_TIME=$(date +%T) 28 | rlRun "printf 'syslog_log: udp:127.0.0.1:514\n' >> /etc/dnsconfd.conf" 0 "Enabling syslog logging with udp" 29 | rlServiceStart rsyslog 30 | rlServiceStart dnsconfd 31 | sleep 3 32 | rlRun "journalctl --since \"$CUR_TIME\" | grep 'ContextState.RUNNING'" 0 "verify logs are indeed in syslog" 33 | rlPhaseEnd 34 | 35 | rlPhaseStartCleanup 36 | rlRun "journalctl -u dnsconfd" 0 "Saving dnsconfd logs" 37 | rlRun "journalctl -u unbound" 0 "Saving unbound logs" 38 | rlRun "ip route" 0 "Saving present routes" 39 | rlServiceRestore dnsconfd 40 | rlServiceRestore rsyslog 41 | rlFileRestore 42 | rlRun "journalctl -u dnsconfd" 0 "Saving logs" 43 | rlRun "dnsconfd config uninstall" 0 "Uninstalling dnsconfd privileges" 44 | rlPhaseEnd 45 | rlJournalEnd 46 | -------------------------------------------------------------------------------- /tests/start_issue/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k 3 | . /usr/share/beakerlib/beakerlib.sh || exit 1 4 | 5 | rlJournalStart 6 | rlPhaseStartSetup 7 | rlRun "set -o pipefail" 8 | rlRun "podman network create dnsconfd_network --internal -d=bridge --gateway=192.168.6.1 --subnet=192.168.6.0/24" 9 | # dns=none is neccessary, because otherwise resolv.conf is created and 10 | # mounted by podman as read-only 11 | rlRun "dnsconfd_cid=\$(podman run --privileged -d --dns='none' --network dnsconfd_network:ip=192.168.6.2 dnsconfd_testing:latest)" 0 "Starting dnsconfd container" 12 | rlPhaseEnd 13 | 14 | rlPhaseStartTest 15 | rlRun "podman exec $dnsconfd_cid systemctl start network-online.target" 16 | rlRun "podman exec $dnsconfd_cid systemctl stop dnsconfd" 0 "stop dnsconfd" 17 | rlRun "podman exec $dnsconfd_cid sed -i 's/ExecStart=.*/ExecStart=false/g' /usr/lib/systemd/system/unbound.service" 0 "breaking unbound" 18 | rlRun "podman exec $dnsconfd_cid systemctl daemon-reload" 0 "reload systemd units" 19 | rlRun "podman exec $dnsconfd_cid systemctl start dnsconfd" 1 "start dnsconfd" 20 | rlRun "podman exec $dnsconfd_cid journalctl -u dnsconfd | grep -e 'TIMEOUT' -e 'START_FAIL'" 0 "Checking dnsconfd logs" 21 | rlRun "podman exec $dnsconfd_cid systemctl status dnsconfd" 3 "Verify that dnsconfd is stopped" 22 | rlPhaseEnd 23 | 24 | rlPhaseStartCleanup 25 | rlRun "podman exec $dnsconfd_cid journalctl -u dnsconfd" 0 "Saving dnsconfd logs" 26 | rlRun "podman exec $dnsconfd_cid journalctl -u unbound" 0 "Saving unbound logs" 27 | rlRun "podman exec $dnsconfd_cid ip route" 0 "Saving present routes" 28 | rlRun "podman stop -t 0 $dnsconfd_cid" 0 "Stopping containers" 29 | rlRun "podman container rm $dnsconfd_cid" 0 "Removing containers" 30 | rlRun "podman network rm dnsconfd_network" 0 "Removing networks" 31 | rlPhaseEnd 32 | rlJournalEnd 33 | -------------------------------------------------------------------------------- /tests/named_certs/ca_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFfzCCA2egAwIBAgIUMxmzo6/XJbHhj6uzFtu+fpKY8rEwDQYJKoZIhvcNAQEL 3 | BQAwTzELMAkGA1UEBhMCQ1oxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UE 4 | CgwTRGVmYXVsdCBDb21wYW55IEx0ZDELMAkGA1UEAwwCY2EwHhcNMjQwNTIxMDc0 5 | MzMzWhcNMzQwNTE5MDc0MzMzWjBPMQswCQYDVQQGEwJDWjEVMBMGA1UEBwwMRGVm 6 | YXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRkMQswCQYDVQQD 7 | DAJjYTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAM4OTT4AIbUWO9nM 8 | Y52f4B+PPZ7BNrxSPooeNtDE9u3dE8lSn5KaAZ2wJYK1A2PDuycukjcHpubX1bGR 9 | r0aILdrk8EnrcgZggOHIsARxaLlZ8SNfK7dFffdfBJF+cS1xAfkYzrPxiC4evHWP 10 | Cjnl0v8JgTvK5gX7CEhd3x5+ETtr7gNAekzxTgBu/hmXZYTC4JbQj/6h2/INizdI 11 | 74aMi0EYWKi0l3hFe1bx6EU882ZiKsra1M7RBfpR7ejxMOMz1KMhvPvvo1/OAOlB 12 | On03P5B9k6UfLItzt9bTFC+de/qRVDb6lkWWXhP87G/Z+Ok9/HGmccSYkLJyqIOh 13 | MDGrbfCfAwsawDbtUDzEka202jl0gB3WVFRQ/vjFm8unp5inFqnx4c2+mx5s2CSb 14 | g8Gt1J2fZTQ4HgKYIlM852p+1kqLWmHJy+j/lVBJDNwMj7I6kjRGfG8vDmuHYPCe 15 | bBh7B3utonpY6uOC+kpF2EiSW9wLp5pXaUj+46CA+A9Yp0bRYInQl3FN5KuG+Rh9 16 | Z8/MBHUhh81l3d4w4Gscjl940dD7eEqQp2Q3bqb4Cf1noZCgKt6Pp5JqVT3zMml4 17 | 6D164Z7ZsnVDn3ax2F1yhX86uZs2De8lMPFd6JXk3FFZwxl4Xn2FBabzQNMz4vOh 18 | L3vg0KWz3nhbv3WXd7e7V5H3onZ5AgMBAAGjUzBRMB0GA1UdDgQWBBS1JDMRP9UN 19 | 9pFch/b70FUIMx5TSjAfBgNVHSMEGDAWgBS1JDMRP9UN9pFch/b70FUIMx5TSjAP 20 | BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQCGvUBPl6Pk466DBKDO 21 | YbIf4fmdx0c7sl/HVhYrg/W2tzGwMh9ORzvDI4MpTcgwxuJK/14xfJu9nIwoNDdI 22 | 1WoVo7p1bzUFqi7QairYKn84xBWYzQfsPTz4yYzG9YsM99jqip6ZCqSkzYcFGnD6 23 | DxknTQ70lDwFdPEQx70qGwmdJKfT1e0Bpb26wJRRLcZokXDNomN/tyydrbOOCZhf 24 | lnMtJ0pSbK/YAykzw1rjkFZt0oS7XXubZ+sL1ph16SX/RksT7tJNjabXdyY0f8N2 25 | f3I+u0F9RA+R10O5mxvAcwcFMGHJ+Wq46K3xe99aonl6Y6yxEDdOUPxwPUiVAzmI 26 | fSpn18tn336auWBqRQNOebVtFYpTHQ9rrp+/QTCkbUYCTU2PRwgQhRZ+QR7qJBsp 27 | J2pKGijHoCW3wfX41qtBy726DZa4biqHCnQ1TwypK5Yt5nMvhJHxdXWDhK4J3Hcr 28 | wcSXLgxx0R04hfTDo88PmA0cJtQb66OYwCxkuRruzujdS0luz92HdHLbDX7Q+feW 29 | ElcjyRZ8B+nK/fL5WdZQc5mgnSSUSseUXB6dJTi/7qtPxee+ctvDWLRwy9QUav1C 30 | fB899Do30eU1DBNAReqc53VE3+N/VDnwJzmccPoB12Q6Rd6cVuocqqBRcq3cxbTQ 31 | e+Hj8NiStOXiFeonHZCwk9/ETQ== 32 | -----END CERTIFICATE----- 33 | -------------------------------------------------------------------------------- /tests/invalid_config/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k 3 | . /usr/share/beakerlib/beakerlib.sh || exit 1 4 | 5 | rlJournalStart 6 | rlPhaseStartSetup 7 | rlRun "podman network create dnsconfd_network --internal -d=bridge --gateway=192.168.6.1 --subnet=192.168.6.0/24" 8 | # dns=none is neccessary, because otherwise resolv.conf is created and 9 | # mounted by podman as read-only 10 | rlRun "dnsconfd_cid=\$(podman run --privileged -d --dns='none' --network dnsconfd_network:ip=192.168.6.2 dnsconfd_testing:latest)" 0 "Starting dnsconfd container" 11 | rlPhaseEnd 12 | 13 | rlPhaseStartTest 14 | rlRun "podman exec $dnsconfd_cid systemctl start network-online.target" 15 | rlRun "podman exec $dnsconfd_cid /bin/bash -c 'echo nonsense > /etc/dnsconfd.conf' " 16 | rlRun "podman exec $dnsconfd_cid systemctl restart dnsconfd" 0 "restart dnsconfd" 17 | rlRun "podman exec $dnsconfd_cid journalctl -u dnsconfd | grep 'Configuration could not be parsed as YAML'" 0 "Checking dnsconfd logs" 18 | rlRun "podman exec $dnsconfd_cid systemctl status dnsconfd" 0 "Verify that dnsconfd is running" 19 | rlRun "podman exec $dnsconfd_cid /bin/bash -c 'echo listen_address: \"nonsense\" > /etc/dnsconfd.conf'" 20 | rlRun "podman exec $dnsconfd_cid systemctl restart dnsconfd" 1 "restart dnsconfd" 21 | rlRun "podman exec $dnsconfd_cid systemctl status dnsconfd | grep 'status=13'" 0 "Verify that dnsconfd refused bad option" 22 | rlPhaseEnd 23 | 24 | rlPhaseStartCleanup 25 | rlRun "podman exec $dnsconfd_cid journalctl -u dnsconfd" 0 "Saving dnsconfd logs" 26 | rlRun "podman exec $dnsconfd_cid journalctl -u unbound" 0 "Saving unbound logs" 27 | rlRun "podman exec $dnsconfd_cid ip route" 0 "Saving present routes" 28 | rlRun "podman stop -t 0 $dnsconfd_cid" 0 "Stopping containers" 29 | rlRun "podman container rm $dnsconfd_cid" 0 "Removing containers" 30 | rlRun "podman network rm dnsconfd_network" 0 "Removing networks" 31 | rlPhaseEnd 32 | rlJournalEnd 33 | -------------------------------------------------------------------------------- /micro-dnsconfd/dbus-handling.c: -------------------------------------------------------------------------------- 1 | #include "dbus-handling.h" 2 | 3 | #include 4 | 5 | GVariantDict *get_glob_dict() { 6 | GError *connection_error = NULL; 7 | GError *proxy_error = NULL; 8 | GError *call_error = NULL; 9 | GVariant *result_unwrapped; 10 | GDBusConnection *connection; 11 | GDBusProxy *proxy; 12 | GVariant *result; 13 | GVariantDict *glob_dict; 14 | 15 | connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &connection_error); 16 | if (connection_error) { 17 | g_error_free(connection_error); 18 | fprintf(stderr, "Could not connect to system DBus\n"); 19 | return NULL; 20 | } 21 | 22 | proxy = g_dbus_proxy_new_sync( 23 | connection, G_DBUS_PROXY_FLAGS_NONE, NULL, 24 | "org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", 25 | "org.freedesktop.DBus.Properties", NULL, &proxy_error); 26 | if (proxy_error) { 27 | g_error_free(proxy_error); 28 | fprintf(stderr, "Could not connect to NetworkManager\n"); 29 | g_dbus_connection_close_sync(connection, NULL, NULL); 30 | g_object_unref(connection); 31 | return NULL; 32 | } 33 | 34 | result = g_dbus_proxy_call_sync( 35 | proxy, "Get", 36 | g_variant_new("(ss)", "org.freedesktop.NetworkManager", 37 | "GlobalDnsConfiguration"), 38 | G_DBUS_CALL_FLAGS_NONE, 5000, NULL, &call_error); 39 | g_object_unref(proxy); 40 | g_dbus_connection_close_sync(connection, NULL, &connection_error); 41 | g_object_unref(connection); 42 | 43 | if (call_error) { 44 | g_error_free(call_error); 45 | fprintf(stderr, "Was not able to retrieve global DNS config\n"); 46 | } 47 | if (connection_error) { 48 | g_error_free(connection_error); 49 | fprintf(stderr, "Was not able to close DBus connection\n"); 50 | } 51 | 52 | if (call_error || connection_error) { 53 | return NULL; 54 | } 55 | 56 | g_variant_get(result, "(v)", &result_unwrapped); 57 | 58 | g_variant_unref(result); 59 | 60 | glob_dict = g_variant_dict_new(result_unwrapped); 61 | g_variant_unref(result_unwrapped); 62 | 63 | if (glob_dict == NULL) { 64 | fprintf(stderr, "Out of memory\n"); 65 | } 66 | return glob_dict; 67 | } 68 | -------------------------------------------------------------------------------- /tests/initramfs_support/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k 3 | . /usr/share/beakerlib/beakerlib.sh || exit 1 4 | . "$TMT_TOPOLOGY_BASH" 5 | 6 | rlJournalStart 7 | rlPhaseStartSetup 8 | rlRun "set -o pipefail" 9 | rlPhaseEnd 10 | 11 | rlPhaseStartTest 12 | if [ "${TMT_GUEST[name]}" = "client" ]; then 13 | if [ "$TMT_REBOOT_COUNT" -eq 0 ]; then 14 | rlRun "ncat -l 8888" 15 | rlRun "mkdir -p /etc/pki/dns/extracted/pem/" 16 | rlRun "cp ca_cert.pem /etc/pki/dns/extracted/pem/tls-ca-bundle.pem" 17 | rlRun "mkdir -p /lib/dracut/modules.d/99test-resolve" 18 | rlRun "cp ./module-setup.sh /lib/dracut/modules.d/99test-resolve" 19 | rlRun "cp ./test-resolve.service /lib/dracut/modules.d/99test-resolve" 20 | rlRun "cp ./test-resolve.service /usr/lib/systemd/system/test-resolve.service" 21 | rlRun "sed -i 's/\(GRUB_CMDLINE_LINUX.*=\".*\)\"/\1 rd.neednet rd.net.dns=dns+tls:\/\/${TMT_GUESTS[server.hostname]}#named ip=dhcp\"/g' /etc/default/grub" 22 | rlRun "grubby --update-kernel=/boot/vmlinuz-$(uname -r) --args=\"rd.neednet rd.net.dns=dns+tls://${TMT_GUESTS[server.hostname]}#named ip=dhcp rd.net.dns-global-mode=exclusive rd.net.dns-backend=dnsconfd\"" 23 | rlRun "dracut --force" 0 "Rebuild initramfs" 24 | rlRun "grub2-mkconfig -o /boot/grub2/grub.cfg" 25 | rlRun "tmt-reboot" 0 "Reboot the machine" 26 | else 27 | rlRun "journalctl -u test-resolve | grep 192.168.6.5" 28 | rlRun "journalctl -u test-resolve" 29 | rlRun "journalctl -u micro-dnsconfd" 30 | rlRun "journalctl -u unbound" 31 | rlRun "journalctl -u NetworkManager" 32 | rlRun "while ! echo 'finish' | ncat ${TMT_GUESTS[server.hostname]} 8888; do sleep 2; done" 33 | fi 34 | else 35 | rlRun "while ! echo 'start' | ncat ${TMT_GUESTS[client.hostname]} 8888; do sleep 2; done" 36 | rlRun "journalctl -u named" 37 | rlRun "ncat -l 8888" 38 | fi 39 | rlPhaseEnd 40 | 41 | rlPhaseStartCleanup 42 | 43 | rlPhaseEnd 44 | rlJournalEnd 45 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | sys.path.insert(0, os.path.abspath('..')) 16 | 17 | 18 | # -- Project information ----------------------------------------------------- 19 | 20 | project = 'dnsconfd' 21 | copyright = '2023, Tomas Korbar, Petr Mensik' 22 | author = 'Tomas Korbar, Petr Mensik' 23 | 24 | # The full version, including alpha/beta/rc tags 25 | release = '1.7.3' 26 | 27 | 28 | # -- General network_objects --------------------------------------------------- 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be 31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 32 | # ones. 33 | extensions = [ 34 | 'sphinx.ext.autodoc', 35 | 'sphinx.ext.viewcode', 36 | 'sphinx.ext.napoleon' 37 | ] 38 | 39 | # Add any paths that contain templates here, relative to this directory. 40 | templates_path = [] 41 | 42 | # List of patterns, relative to source directory, that match files and 43 | # directories to ignore when looking for source files. 44 | # This pattern also affects html_static_path and html_extra_path. 45 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 46 | 47 | autoclass_content = 'both' 48 | 49 | # -- Options for HTML output ------------------------------------------------- 50 | 51 | # The theme to use for HTML and HTML Help pages. See the documentation for 52 | # a list of builtin themes. 53 | # 54 | html_theme = 'sphinx_rtd_theme' 55 | 56 | # Add any paths that contain custom static files (such as style sheets) here, 57 | # relative to this directory. They are copied after the builtin static files, 58 | # so a file named "default.css" will overwrite the builtin "default.css". 59 | html_static_path = [] 60 | add_module_names = False 61 | -------------------------------------------------------------------------------- /bin/dnsconfd: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import logging 3 | 4 | from dnsconfd.input_modules import ResolveDbusInterface, DnsconfdDbusInterface 5 | from dnsconfd.fsm import ContextEvent 6 | from dnsconfd.fsm import DnsconfdContext 7 | from dnsconfd.configuration import DnsconfdArgumentParser as ArgParser 8 | from dnsconfd.exit_code import ExitCode 9 | 10 | import sys 11 | import signal 12 | import dbus.mainloop.glib 13 | from gi.repository import GLib 14 | 15 | if __name__ == "__main__": 16 | parser = ArgParser(prog='dnsconfd', 17 | description='local DNS cache configuration daemon') 18 | parser.add_arguments() 19 | parser.add_commands() 20 | try: 21 | args = parser.parse_args() 22 | except ValueError: 23 | sys.exit(ExitCode.BAD_ARGUMENTS.value) 24 | 25 | # This ensures that proper handler is called if command is provided, else 26 | # noop and execution returns here 27 | args.func() 28 | 29 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 30 | config = vars(args) 31 | main_loop = GLib.MainLoop() 32 | ctx = DnsconfdContext(config, main_loop) 33 | # this has to happen before we expose the API 34 | GLib.idle_add(lambda: ctx.transition_function(ContextEvent("KICKOFF"))) 35 | lgr = logging.getLogger("dnsconfd") 36 | try: 37 | if config["api_choice"] == "resolve1": 38 | input_module = ResolveDbusInterface(ctx, config) 39 | else: 40 | input_module = DnsconfdDbusInterface(ctx, config) 41 | ctx.set_signal_emitter(input_module.emit_serial_signal) 42 | except dbus.DBusException as e: 43 | lgr.critical("Failed to connect to DBUS, check your policy %s", e) 44 | sys.exit(ExitCode.DBUS_FAILURE.value) 45 | 46 | # using lambdas here allows us to not use exit in DnsconfdContext class 47 | signal.signal(signal.SIGTERM, 48 | lambda signum, frame: 49 | GLib.idle_add(lambda: 50 | ctx.transition_function(ContextEvent("STOP")))) 51 | 52 | signal.signal(signal.SIGINT, 53 | lambda signum, frame: 54 | GLib.idle_add(lambda: 55 | ctx.transition_function(ContextEvent("STOP")))) 56 | main_loop.run() 57 | sys.exit(ctx.get_exit_code()) 58 | -------------------------------------------------------------------------------- /tests/named.conf: -------------------------------------------------------------------------------- 1 | // 2 | // named.conf 3 | // 4 | // Provided by Red Hat bind package to configure the ISC BIND named(8) DNS 5 | // server as a caching only nameserver (as a localhost DNS resolver only). 6 | // 7 | // See /usr/share/doc/bind*/sample/ for example named configuration files. 8 | // 9 | 10 | tls mytls { 11 | cert-file "/etc/named/my_signed_cert.pem"; 12 | key-file "/etc/named/my_private_key.pem"; 13 | }; 14 | 15 | options { 16 | listen-on port 53 { any; }; 17 | listen-on-v6 port 53 { ::1; }; 18 | directory "/var/named"; 19 | dump-file "/var/named/data/cache_dump.db"; 20 | statistics-file "/var/named/data/named_stats.txt"; 21 | memstatistics-file "/var/named/data/named_mem_stats.txt"; 22 | secroots-file "/var/named/data/named.secroots"; 23 | recursing-file "/var/named/data/named.recursing"; 24 | allow-query { any; }; 25 | 26 | listen-on port 853 tls mytls { any; }; 27 | /* 28 | - If you are building an AUTHORITATIVE DNS server, do NOT enable recursion. 29 | - If you are building a RECURSIVE (caching) DNS server, you need to enable 30 | recursion. 31 | - If your recursive DNS server has a public IP address, you MUST enable access 32 | control to limit queries to your legitimate users. Failing to do so will 33 | cause your server to become part of large scale DNS amplification 34 | attacks. Implementing BCP38 within your network would greatly 35 | reduce such attack surface 36 | */ 37 | recursion no; 38 | 39 | dnssec-validation yes; 40 | 41 | 42 | managed-keys-directory "/var/named/dynamic"; 43 | geoip-directory "/usr/share/GeoIP"; 44 | 45 | pid-file "/run/named/named.pid"; 46 | session-keyfile "/run/named/session.key"; 47 | 48 | /* https://fedoraproject.org/wiki/Changes/CryptoPolicy */ 49 | include "/etc/crypto-policies/back-ends/bind.config"; 50 | }; 51 | 52 | logging { 53 | channel default_debug { 54 | file "data/named.run"; 55 | severity dynamic; 56 | }; 57 | }; 58 | 59 | zone "." IN { 60 | type hint; 61 | file "named.ca"; 62 | }; 63 | 64 | zone "com" IN { 65 | type primary; 66 | file "/etc/named/com.signed"; 67 | }; 68 | 69 | zone "example.com" IN { 70 | type primary; 71 | file "/etc/named/example.com.signed"; 72 | }; 73 | 74 | include "/etc/named.rfc1912.zones"; 75 | include "/etc/named.root.key"; 76 | -------------------------------------------------------------------------------- /tests/named2.conf: -------------------------------------------------------------------------------- 1 | // 2 | // named.conf 3 | // 4 | // Provided by Red Hat bind package to configure the ISC BIND named(8) DNS 5 | // server as a caching only nameserver (as a localhost DNS resolver only). 6 | // 7 | // See /usr/share/doc/bind*/sample/ for example named configuration files. 8 | // 9 | 10 | tls mytls { 11 | cert-file "/etc/named/my_signed_cert2.pem"; 12 | key-file "/etc/named/my_private_key2.pem"; 13 | }; 14 | 15 | options { 16 | listen-on port 53 { any; }; 17 | listen-on-v6 port 53 { ::1; }; 18 | directory "/var/named"; 19 | dump-file "/var/named/data/cache_dump.db"; 20 | statistics-file "/var/named/data/named_stats.txt"; 21 | memstatistics-file "/var/named/data/named_mem_stats.txt"; 22 | secroots-file "/var/named/data/named.secroots"; 23 | recursing-file "/var/named/data/named.recursing"; 24 | allow-query { any; }; 25 | 26 | listen-on port 853 tls mytls { any; }; 27 | /* 28 | - If you are building an AUTHORITATIVE DNS server, do NOT enable recursion. 29 | - If you are building a RECURSIVE (caching) DNS server, you need to enable 30 | recursion. 31 | - If your recursive DNS server has a public IP address, you MUST enable access 32 | control to limit queries to your legitimate users. Failing to do so will 33 | cause your server to become part of large scale DNS amplification 34 | attacks. Implementing BCP38 within your network would greatly 35 | reduce such attack surface 36 | */ 37 | recursion no; 38 | 39 | dnssec-validation yes; 40 | 41 | 42 | managed-keys-directory "/var/named/dynamic"; 43 | geoip-directory "/usr/share/GeoIP"; 44 | 45 | pid-file "/run/named/named.pid"; 46 | session-keyfile "/run/named/session.key"; 47 | 48 | /* https://fedoraproject.org/wiki/Changes/CryptoPolicy */ 49 | include "/etc/crypto-policies/back-ends/bind.config"; 50 | }; 51 | 52 | logging { 53 | channel default_debug { 54 | file "data/named.run"; 55 | severity dynamic; 56 | }; 57 | }; 58 | 59 | zone "." IN { 60 | type hint; 61 | file "named.ca"; 62 | }; 63 | 64 | zone "com" IN { 65 | type primary; 66 | file "/etc/named/com.signed"; 67 | }; 68 | 69 | zone "example.com" IN { 70 | type primary; 71 | file "/etc/named/example.com.signed"; 72 | }; 73 | 74 | include "/etc/named.rfc1912.zones"; 75 | include "/etc/named.root.key"; 76 | -------------------------------------------------------------------------------- /.packit.yaml: -------------------------------------------------------------------------------- 1 | # See the documentation for more information: 2 | # https://packit.dev/docs/configuration/ 3 | 4 | specfile_path: distribution/dnsconfd.spec 5 | 6 | # add or remove files that should be synced 7 | files_to_sync: 8 | - distribution/dnsconfd.spec 9 | - .packit.yaml 10 | 11 | # name in upstream package repository or registry (e.g. in PyPI) 12 | upstream_package_name: dnsconfd 13 | # downstream (Fedora) RPM package name 14 | downstream_package_name: dnsconfd 15 | 16 | update_release: false 17 | actions: 18 | get-current-version: "sed -n 's|^Version: *||p' distribution/dnsconfd.spec" 19 | 20 | jobs: 21 | # pr jobs 22 | - job: copr_build 23 | trigger: pull_request 24 | identifier: pr_copr_build 25 | targets: 26 | - fedora-42 27 | - fedora-rawhide 28 | - centos-stream-10 29 | - centos-stream-9 30 | - job: tests 31 | trigger: pull_request 32 | identifier: pr_tests_multihost 33 | targets: 34 | - fedora-42 35 | - fedora-rawhide 36 | - centos-stream-10 37 | - centos-stream-9 38 | tmt_plan: multihost 39 | skip_build: True 40 | tf_extra_params: 41 | settings: 42 | pipeline: 43 | type: tmt-multihost 44 | use_internal_tf: True 45 | - job: tests 46 | trigger: pull_request 47 | identifier: pr_tests_singlehost 48 | targets: 49 | - fedora-42 50 | - fedora-rawhide 51 | - centos-stream-10 52 | - centos-stream-9 53 | tmt_plan: "(integration|distribution|unit)" 54 | skip_build: True 55 | # commit jobs (executed on main branch) 56 | - job: copr_build 57 | trigger: commit 58 | identifier: commit_copr_build 59 | targets: 60 | - fedora-42 61 | - fedora-rawhide 62 | - centos-stream-10 63 | - centos-stream-9 64 | - job: tests 65 | trigger: commit 66 | identifier: pr_tests_multihost 67 | targets: 68 | - fedora-42 69 | - fedora-rawhide 70 | - centos-stream-10 71 | - centos-stream-9 72 | tmt_plan: multihost 73 | skip_build: True 74 | tf_extra_params: 75 | settings: 76 | pipeline: 77 | type: tmt-multihost 78 | use_internal_tf: True 79 | - job: tests 80 | trigger: commit 81 | identifier: pr_tests_singlehost 82 | targets: 83 | - fedora-42 84 | - fedora-rawhide 85 | - centos-stream-10 86 | - centos-stream-9 87 | tmt_plan: "(integration|distribution|unit)" 88 | skip_build: True 89 | -------------------------------------------------------------------------------- /plans/integration.fmf: -------------------------------------------------------------------------------- 1 | summary: Run integration tests with tmt 2 | discover: 3 | how: fmf 4 | filter: tag:integration 5 | execute: 6 | how: tmt 7 | prepare: 8 | - name: packages 9 | order: 4 10 | how: install 11 | package: 12 | - podman 13 | - beakerlib 14 | - python3-devel 15 | - python3-setuptools 16 | - python3-rpm-macros 17 | - python3-pip 18 | - python3-pyyaml 19 | - python3-systemd 20 | - python3-idna 21 | - systemd 22 | - rpm-build 23 | - systemd-rpm-macros 24 | - selinux-policy-devel 25 | - selinux-policy-targeted 26 | - audit 27 | - dbus-tools 28 | - rsyslog 29 | - jq 30 | - pkgconfig(glib-2.0) 31 | - pkgconfig(gio-2.0) 32 | - pkgconfig(libcurl) 33 | - pkgconfig(check) 34 | - pkgconfig(libsystemd) 35 | - gcc 36 | - cmake 37 | - name: build-package 38 | order: 5 39 | how: shell 40 | script: ./tests/build_package.sh 41 | - name: build-base-container 42 | order: 6 43 | how: shell 44 | script: ./tests/build_ostree.sh 45 | - name: build-containers 46 | order: 7 47 | how: shell 48 | script: ./tests/build_images.sh 49 | - name: install-package 50 | order: 8 51 | how: shell 52 | script: dnf install -y ./tests/*.rpm 53 | adjust: 54 | - when: trigger is not defined or trigger == human 55 | provision: 56 | how: virtual 57 | image: fedora-rawhide 58 | - when: distro == centos-stream or distro == rhel 59 | prepare+: 60 | - how: shell 61 | name: enable CRB 62 | order: 1 63 | script: 'dnf config-manager --set-enabled crb || dnf config-manager --set-enabled rhel-CRB || dnf config-manager --set-enabled beaker-CRB' 64 | - when: distro == centos-stream-9 or distro == rhel-9 65 | prepare+: 66 | - how: install 67 | name: install EPEL 68 | order: 2 69 | package: 70 | - https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm 71 | - when: distro == centos-stream-10 or distro == rhel-10 72 | prepare+: 73 | - how: install 74 | name: install EPEL 75 | order: 2 76 | package: 77 | - https://dl.fedoraproject.org/pub/epel/epel-release-latest-10.noarch.rpm 78 | - when: distro == centos-stream or distro == rhel 79 | prepare+: 80 | - how: shell 81 | name: enable EPEL 82 | order: 3 83 | script: 'dnf config-manager --set-enabled epel' 84 | -------------------------------------------------------------------------------- /micro-dnsconfd/tests/test-uri-parsing.c: -------------------------------------------------------------------------------- 1 | #include "test-uri-parsing.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "uri-parsing.h" 7 | 8 | typedef struct { 9 | char *input; 10 | char *output; 11 | unsigned char is_domain_tls; 12 | unsigned char return_code; 13 | } ioTuple; 14 | 15 | static ioTuple io_tuples[] = { 16 | {"8.8.8.8", "\tforward-addr: 8.8.8.8\n", 0, 0}, 17 | {"dns+tls://8.8.8.8", "\tforward-addr: 8.8.8.8\n", 1, 0}, 18 | {"dns+tls://8.8.8.8:55", "\tforward-addr: 8.8.8.8@55\n", 1, 0}, 19 | {"dns+tls://8.8.8.8:55#example.org", 20 | "\tforward-addr: 8.8.8.8@55#example.org\n", 1, 0}, 21 | {"dns+udp://8.8.8.8", "\tforward-addr: 8.8.8.8\n", 0, 0}, 22 | {"dns+udp://8.8.8.8:55", "\tforward-addr: 8.8.8.8@55\n", 0, 0}, 23 | {"dns+udp://8.8.8.8#example.org", "\tforward-addr: 8.8.8.8#example.org\n", 24 | 0, 0}, 25 | {"dns+tls://[::1]", "\tforward-addr: ::1\n", 1, 0}, 26 | {"dns+tls://[::1]:55", "\tforward-addr: ::1@55\n", 1, 0}, 27 | {"dns+tls://[::1]:55#example.org", "\tforward-addr: ::1@55#example.org\n", 28 | 1, 0}, 29 | {"dns+udp://[::1]", "\tforward-addr: ::1\n", 0, 0}, 30 | {"dns+udp://[::1]:55", "\tforward-addr: ::1@55\n", 0, 0}, 31 | {"dns+udp://[::1]#example.org", "\tforward-addr: ::1#example.org\n", 0, 0}, 32 | {"500.8.8.8", NULL, 0, 1}, 33 | {"dns+whatever://8.8.8.8", NULL, 1, 1}, 34 | {"dns+tls://[8.8.8.8", NULL, 1, 1}, 35 | {"dns+tls://[", NULL, 1, 1}, 36 | {0}}; 37 | 38 | START_TEST(test_parsing) { 39 | GString *config_string = g_string_new(NULL); 40 | unsigned char domain_tls; 41 | ioTuple *cur_tuple = &io_tuples[0]; 42 | 43 | FILE *dev_null = fopen("/dev/null", "w"); 44 | 45 | for (int i = 0; cur_tuple->input != 0; i++, cur_tuple = &io_tuples[i]) { 46 | domain_tls = 0; 47 | ck_assert(transform_server_string(cur_tuple->input, &domain_tls, 48 | config_string, 49 | dev_null) == cur_tuple->return_code); 50 | if (!cur_tuple->return_code) { 51 | ck_assert(domain_tls == cur_tuple->is_domain_tls); 52 | ck_assert(strcmp(config_string->str, cur_tuple->output) == 0); 53 | } 54 | g_string_truncate(config_string, 0); 55 | } 56 | g_string_free(config_string, 1); 57 | fclose(dev_null); 58 | } 59 | END_TEST 60 | 61 | Suite *uri_parsing_suite() { 62 | Suite *s; 63 | TCase *tc_core; 64 | 65 | s = suite_create("uri-parsing"); 66 | tc_core = tcase_create("Core"); 67 | 68 | tcase_add_test(tc_core, test_parsing); 69 | suite_add_tcase(s, tc_core); 70 | return s; 71 | } 72 | -------------------------------------------------------------------------------- /tests/reload/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k 3 | . /usr/share/beakerlib/beakerlib.sh || exit 1 4 | . ../dnsconfd_helper_functions.sh || exit 1 5 | ORIG_DIR=$(pwd) 6 | 7 | rlJournalStart 8 | rlPhaseStartSetup 9 | rlRun "tmp=\$(mktemp -d)" 0 "Create tmp directory" 10 | rlRun "pushd $tmp" 11 | rlRun "set -o pipefail" 12 | rlRun "podman network create dnsconfd_network --internal -d=bridge --gateway=192.168.6.1 --subnet=192.168.6.0/24" 13 | # dns=none is neccessary, because otherwise resolv.conf is created and 14 | # mounted by podman as read-only 15 | rlRun "dnsconfd_cid=\$(podman run -d --privileged --dns='none' --network dnsconfd_network:ip=192.168.6.2 dnsconfd_testing:latest)" 0 "Starting dnsconfd container" 16 | rlRun "dnsmasq_cid=\$(podman run -d --dns='none' --network dnsconfd_network:ip=192.168.6.3 localhost/dnsconfd_utilities:latest dnsmasq_entry.sh --listen-address=192.168.6.3 --address=/address.test.com/192.168.6.3)" 0 "Starting dnsmasq container" 17 | rlPhaseEnd 18 | 19 | rlPhaseStartTest 20 | rlRun "podman exec $dnsconfd_cid systemctl start network-online.target" 21 | rlRun "podman exec $dnsconfd_cid nmcli connection mod eth0 ipv4.dns 192.168.6.3" 0 "Adding dns server to NM active profile" 22 | rlRun "podman exec $dnsconfd_cid nmcli con up eth0" 23 | # FIXME workaround of NM DAD issue 24 | rlRun "podman exec $dnsconfd_cid nmcli g reload" 25 | rlRun "podman exec $dnsconfd_cid dnsconfd reload" 26 | sleep 8 27 | rlRun "podman exec $dnsconfd_cid dnsconfd status --json | jq_filter_general > status1" 0 "Getting status of dnsconfd" 28 | rlAssertNotDiffer status1 $ORIG_DIR/expected_status.json 29 | rlRun "podman exec $dnsconfd_cid getent hosts address.test.com | grep 192.168.6.3" 0 "Verifying correct address resolution" 30 | rlPhaseEnd 31 | 32 | rlPhaseStartCleanup 33 | rlRun "podman exec $dnsconfd_cid journalctl -u dnsconfd" 0 "Saving dnsconfd logs" 34 | rlRun "podman exec $dnsconfd_cid journalctl -u unbound" 0 "Saving unbound logs" 35 | rlRun "podman exec $dnsconfd_cid ip route" 0 "Saving present routes" 36 | rlRun "popd" 37 | rlRun "podman stop -t 0 $dnsconfd_cid $dnsmasq_cid" 0 "Stopping containers" 38 | rlRun "podman container rm $dnsconfd_cid $dnsmasq_cid" 0 "Removing containers" 39 | rlRun "podman network rm dnsconfd_network" 0 "Removing networks" 40 | rlRun "rm -r $tmp" 0 "Remove tmp directory" 41 | rlPhaseEnd 42 | rlJournalEnd 43 | -------------------------------------------------------------------------------- /tests/logging/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k 3 | . /usr/share/beakerlib/beakerlib.sh || exit 1 4 | ORIG_DIR=$(pwd) 5 | 6 | rlJournalStart 7 | rlPhaseStartSetup 8 | rlRun "tmp=\$(mktemp -d)" 0 "Create tmp directory" 9 | rlRun "cp rsyslog.conf $tmp" 10 | rlRun "pushd $tmp" 11 | rlRun "set -o pipefail" 12 | # dns=none is neccessary, because otherwise resolv.conf is created and 13 | # mounted by podman as read-only 14 | rlRun "dnsconfd_cid=\$(podman run --privileged -d --dns='none' dnsconfd_testing:latest)" 0 "Starting dnsconfd container" 15 | rlPhaseEnd 16 | 17 | rlPhaseStartTest 18 | rlRun "podman exec $dnsconfd_cid systemctl start network-online.target" 19 | rlRun "podman exec $dnsconfd_cid touch /var/run/dnsconfd/dnsconfd.log" 0 "Create log file" 20 | rlRun "podman exec $dnsconfd_cid chown dnsconfd /var/run/dnsconfd/dnsconfd.log" 0 "Set log file ownership" 21 | rlRun "podman exec $dnsconfd_cid /bin/bash -c 'printf \"file_log: /var/run/dnsconfd/dnsconfd.log\n\" >> /etc/dnsconfd.conf'" 0 "Enabling file logging" 22 | rlRun "podman exec $dnsconfd_cid systemctl restart dnsconfd" 23 | rlRun "podman exec $dnsconfd_cid systemctl start network-online.target" 24 | rlRun "podman exec $dnsconfd_cid cat /var/run/dnsconfd/dnsconfd.log | grep 'ContextState.RUNNING'" 0 "verify logs are indeed in file" 25 | rlRun "podman exec $dnsconfd_cid systemctl stop rsyslog" 26 | rlRun "podman exec $dnsconfd_cid /bin/bash -c 'echo \"\" > /var/log/messages'" 27 | # now we will test syslog logging 28 | rlRun "podman cp rsyslog.conf $dnsconfd_cid:/etc/rsyslog.conf" 29 | rlRun "podman exec $dnsconfd_cid systemctl start rsyslog" 30 | rlRun "podman exec $dnsconfd_cid /bin/bash -c 'printf \"syslog_log: unix:/dev/newlog\n\" >> /etc/dnsconfd.conf'" 0 "Enabling syslog logging" 31 | rlRun "podman exec $dnsconfd_cid systemctl restart dnsconfd" 32 | rlRun "podman exec $dnsconfd_cid systemctl start network-online.target" 33 | rlRun "podman exec $dnsconfd_cid cat /var/log/messages | grep 'ContextState.RUNNING'" 0 "verify logs are indeed in syslog" 34 | rlPhaseEnd 35 | 36 | rlPhaseStartCleanup 37 | rlRun "podman exec $dnsconfd_cid journalctl -u dnsconfd" 0 "Saving dnsconfd logs" 38 | rlRun "popd" 39 | rlRun "podman stop -t 0 $dnsconfd_cid" 0 "Stopping containers" 40 | rlRun "podman container rm $dnsconfd_cid" 0 "Removing containers" 41 | rlRun "rm -r $tmp" 0 "Remove tmp directory" 42 | rlPhaseEnd 43 | rlJournalEnd 44 | -------------------------------------------------------------------------------- /plans/distribution.fmf: -------------------------------------------------------------------------------- 1 | summary: Run distribution tests with tmt 2 | discover: 3 | how: fmf 4 | filter: tag:distribution 5 | execute: 6 | how: tmt 7 | prepare: 8 | - name: packages 9 | order: 4 10 | how: install 11 | package: 12 | - beakerlib 13 | - python3-devel 14 | - python3-setuptools 15 | - python3-rpm-macros 16 | - python3-pip 17 | - python3-pyyaml 18 | - python3-systemd 19 | - python3-idna 20 | - systemd 21 | - rpm-build 22 | - systemd-rpm-macros 23 | - selinux-policy-devel 24 | - selinux-policy-targeted 25 | - audit 26 | - dbus-tools 27 | - rsyslog 28 | - jq 29 | - pkgconfig(glib-2.0) 30 | - pkgconfig(gio-2.0) 31 | - pkgconfig(libcurl) 32 | - pkgconfig(check) 33 | - pkgconfig(libsystemd) 34 | - gcc 35 | - cmake 36 | - name: build-package 37 | order: 5 38 | how: shell 39 | script: ./tests/build_package.sh 40 | - name: remove-systemd-resolved 41 | order: 6 42 | how: shell 43 | script: dnf remove -y systemd-resolved 44 | - name: restart-network-manager 45 | order: 7 46 | how: shell 47 | script: systemctl restart NetworkManager 48 | - name: install-package 49 | order: 8 50 | how: shell 51 | script: dnf install -y ./tests/*.rpm 52 | - name: increase-verbosity 53 | order: 9 54 | how: shell 55 | script: "echo 'LOG_LEVEL=DEBUG' >> /etc/sysconfig/dnsconfd && sed -i 's/verbosity.*/verbosity: 5/g' /etc/unbound/unbound.conf" 56 | adjust: 57 | - when: trigger is not defined or trigger == human 58 | provision: 59 | how: virtual 60 | image: fedora-rawhide 61 | - when: distro == centos-stream or distro == rhel 62 | prepare+: 63 | - how: shell 64 | name: enable CRB 65 | order: 1 66 | script: 'dnf config-manager --set-enabled crb || dnf config-manager --set-enabled rhel-CRB || dnf config-manager --set-enabled beaker-CRB' 67 | - when: distro == centos-stream-9 or distro == rhel-9 68 | prepare+: 69 | - how: install 70 | name: install EPEL 71 | order: 2 72 | package: 73 | - https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm 74 | - when: distro == centos-stream-10 or distro == rhel-10 75 | prepare+: 76 | - how: install 77 | name: install EPEL 78 | order: 2 79 | package: 80 | - https://dl.fedoraproject.org/pub/epel/epel-release-latest-10.noarch.rpm 81 | - when: distro == centos-stream or distro == rhel 82 | prepare+: 83 | - how: shell 84 | name: enable EPEL 85 | order: 3 86 | script: 'dnf config-manager --set-enabled epel' -------------------------------------------------------------------------------- /tests/basic/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k 3 | . /usr/share/beakerlib/beakerlib.sh || exit 1 4 | . ../dnsconfd_helper_functions.sh || exit 1 5 | ORIG_DIR=$(pwd) 6 | 7 | rlJournalStart 8 | rlPhaseStartSetup 9 | rlRun "tmp=\$(mktemp -d)" 0 "Create tmp directory" 10 | rlRun "pushd $tmp" 11 | rlRun "set -o pipefail" 12 | rlRun "podman network create dnsconfd_network --internal -d=bridge --gateway=192.168.6.1 --subnet=192.168.6.0/24" 13 | # dns=none is neccessary, because otherwise resolv.conf is created and 14 | # mounted by podman as read-only 15 | rlRun "dnsconfd_cid=\$(podman run --privileged -d --dns='none' --network dnsconfd_network:ip=192.168.6.2 dnsconfd_testing:latest)" 0 "Starting dnsconfd container" 16 | rlRun "dnsmasq_cid=\$(podman run -d --dns='none' --network dnsconfd_network:ip=192.168.6.3 localhost/dnsconfd_utilities:latest dnsmasq_entry.sh --listen-address=192.168.6.3 --address=/address.test.com/192.168.6.3)" 0 "Starting dnsmasq container" 17 | rlPhaseEnd 18 | 19 | rlPhaseStartTest 20 | rlRun "podman exec $dnsconfd_cid systemctl start network-online.target" 0 "Waiting for network setup" 21 | rlRun "podman exec $dnsconfd_cid nmcli connection mod eth0 ipv4.dns 192.168.6.3" 0 "Adding dns server to NM active profile" 22 | rlRun "podman exec $dnsconfd_cid nmcli connection up eth0" 0 "Bringing the connection up" 23 | # FIXME workaround of NM DAD issue 24 | rlRun "podman exec $dnsconfd_cid nmcli g reload" 25 | rlRun "podman exec $dnsconfd_cid nmcli con show eth0" 26 | rlRun "podman exec $dnsconfd_cid dnsconfd status --json | jq_filter_general > status1" 0 "Getting status of dnsconfd" 27 | rlAssertNotDiffer status1 $ORIG_DIR/expected_status.json 28 | rlRun "cat status1" 29 | rlRun "podman exec $dnsconfd_cid getent hosts address.test.com | grep 192.168.6.3" 0 "Verifying correct address resolution" 30 | rlPhaseEnd 31 | 32 | rlPhaseStartCleanup 33 | rlRun "podman exec $dnsconfd_cid journalctl -u dnsconfd" 0 "Saving dnsconfd logs" 34 | rlRun "podman exec $dnsconfd_cid journalctl -u unbound" 0 "Saving unbound logs" 35 | rlRun "podman exec $dnsconfd_cid journalctl -u NetworkManager" 0 "Saving NM logs" 36 | rlRun "podman exec $dnsconfd_cid ip route" 0 "Saving present routes" 37 | rlRun "popd" 38 | rlRun "podman stop -t 0 $dnsconfd_cid $dnsmasq_cid" 0 "Stopping containers" 39 | rlRun "podman container rm $dnsconfd_cid $dnsmasq_cid" 0 "Removing containers" 40 | rlRun "podman network rm dnsconfd_network" 0 "Removing networks" 41 | rlRun "rm -r $tmp" 0 "Remove tmp directory" 42 | rlPhaseEnd 43 | rlJournalEnd 44 | -------------------------------------------------------------------------------- /tests/unbound-stop-recovery/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k 3 | . /usr/share/beakerlib/beakerlib.sh || exit 1 4 | . ../dnsconfd_helper_functions.sh || exit 1 5 | ORIG_DIR=$(pwd) 6 | 7 | rlJournalStart 8 | rlPhaseStartSetup 9 | rlRun "tmp=\$(mktemp -d)" 0 "Create tmp directory" 10 | rlRun "pushd $tmp" 11 | rlRun "set -o pipefail" 12 | rlRun "podman network create dnsconfd_network --internal -d=bridge --gateway=192.168.6.1 --subnet=192.168.6.0/24" 13 | # dns=none is neccessary, because otherwise resolv.conf is created and 14 | # mounted by podman as read-only 15 | rlRun "dnsconfd_cid=\$(podman run --privileged -d --dns='none' --network dnsconfd_network:ip=192.168.6.2 dnsconfd_testing:latest)" 0 "Starting dnsconfd container" 16 | rlRun "dnsmasq_cid=\$(podman run -d --dns='none' --network dnsconfd_network:ip=192.168.6.3 localhost/dnsconfd_utilities:latest dnsmasq_entry.sh --listen-address=192.168.6.3 --address=/address.test.com/192.168.6.3)" 0 "Starting dnsmasq container" 17 | rlPhaseEnd 18 | 19 | rlPhaseStartTest 20 | rlRun "podman exec $dnsconfd_cid systemctl start network-online.target" 21 | rlRun "podman exec $dnsconfd_cid nmcli connection mod eth0 ipv4.dns 192.168.6.3" 0 "Adding dns server to NM active profile" 22 | rlRun "podman exec $dnsconfd_cid nmcli con up eth0" 23 | # FIXME workaround of NM DAD issue 24 | rlRun "podman exec $dnsconfd_cid nmcli g reload" 25 | rlRun "podman exec $dnsconfd_cid dnsconfd status --json | jq_filter_general > status1" 0 "Getting status of dnsconfd" 26 | rlAssertNotDiffer status1 $ORIG_DIR/expected_status.json 27 | rlRun "podman exec $dnsconfd_cid getent hosts address.test.com | grep 192.168.6.3" 0 "Verifying correct address resolution" 28 | rlRun "podman exec $dnsconfd_cid systemctl restart unbound" 0 "Restarting unbound" 29 | sleep 5 30 | rlRun "podman exec $dnsconfd_cid getent hosts address.test.com | grep 192.168.6.3" 0 "Verifying correct address resolution after unbound recovery" 31 | rlPhaseEnd 32 | 33 | rlPhaseStartCleanup 34 | rlRun "podman exec $dnsconfd_cid journalctl -u dnsconfd" 0 "Saving dnsconfd logs" 35 | rlRun "podman exec $dnsconfd_cid journalctl -u unbound" 0 "Saving unbound logs" 36 | rlRun "podman exec $dnsconfd_cid ip route" 0 "Saving present routes" 37 | rlRun "popd" 38 | rlRun "podman stop -t 0 $dnsconfd_cid $dnsmasq_cid" 0 "Stopping containers" 39 | rlRun "podman container rm $dnsconfd_cid $dnsmasq_cid" 0 "Removing containers" 40 | rlRun "podman network rm dnsconfd_network" 0 "Removing networks" 41 | rlRun "rm -r $tmp" 0 "Remove tmp directory" 42 | rlPhaseEnd 43 | rlJournalEnd 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dnsconfd 2 | 3 | Dnsconfd simplifies configuration of local dns caching services by 4 | implementing DBus interface of systemd-resolved and translating its 5 | use to dns service's configuration. 6 | 7 | It is intended to be configured automatically from Network Manager and 8 | to provide nice frontend, similar to resolvectl. Only some its features 9 | are planned however. 10 | 11 | ## How to start it? 12 | 13 | Current version uses systemd-resolved plugin from Network Manager. Therefore it cannot run 14 | together with *systemd-resolved.service* at the same time. 15 | 16 | - ``systemctl disable --now systemd-resolved`` 17 | - ``systemctl mask systemd-resolved`` - prevents conflict of dbus service names 18 | - ``dnsconfd config install`` - modifies NetworkManager to explicitly use systemd-resolved dbus API, 19 | and changes ownership of resolvconf so Dnsconfd does not need root privileges 20 | - ``systemctl enable --now dnsconfd`` 21 | 22 | ## Testing 23 | 24 | You can verify your changes by executing: 25 | 26 | ``` 27 | $ tmt run 28 | ``` 29 | 30 | This executes all test plans currently present for the project. 31 | 32 | ## Distribution 33 | 34 | Dnsconfd is distributed as an RPM package that can be build for testing 35 | purposes by executing `$ ./tests/build_package.sh` 36 | 37 | ## Documentation 38 | 39 | You can build documentation with `$ sphinx-build -M html docs _build` 40 | 41 | There is also a script to build graph of FSM implemented in dnsconfd_context. 42 | `$ python3 docs/generate_fsm.py` 43 | 44 | ## Currently supported DNS caching services 45 | 46 | - [Unbound](https://nlnetlabs.nl/projects/unbound/about/) 47 | 48 | ## Known limitations 49 | 50 | - Unfortunately, intergration with NetworkManager is now only possible 51 | when Dnsconfd is allowed to own 52 | [org.freedesktop.resolve1](https://www.freedesktop.org/software/systemd/man/latest/org.freedesktop.resolve1.html) 53 | DBus name, as NetworkManager does not support use of any another. 54 | - DNSSEC validation is turned off to prevent potential problems. On well 55 | working networks it should work correctly. It disables validation even when 56 | *dnsconfd.service* is not started. 57 | 58 | ## Plans for future 59 | 60 | - Support more cache backends, at least *BIND9* and *dnsmasq*. 61 | - Have special handling of captive portals. Take inspiration from dnssec-trigger. 62 | - Have working DNS over TLS configured via NM. 63 | - Implement own NM dns plugin, allowing us to not conflict with systemd-resolved 64 | - Have a nice frontend ``dnsconfctl``, similar to ``resolvectl``. Present current 65 | configuration in it, have it even localized. 66 | - Support for chain of servers, such as dnsmasq+dnsdist to provide DoT uplink even 67 | for dnsmasq or BIND 9.16 and earlier, which do not support it natively. 68 | - Support configuration from alternative network configuration daemons, like 69 | *systemd-networkd* or *dhcpcd*. 70 | -------------------------------------------------------------------------------- /tests/cleanup/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k 3 | . /usr/share/beakerlib/beakerlib.sh || exit 1 4 | . ../dnsconfd_helper_functions.sh || exit 1 5 | 6 | rlJournalStart 7 | rlPhaseStartSetup 8 | rlRun "tmp=\$(mktemp -d)" 0 "Create tmp directory" 9 | rlRun "cp expected_status.json $tmp" 10 | rlRun "pushd $tmp" 11 | rlRun "podman network create dnsconfd_network --internal -d=bridge --gateway=192.168.6.1 --subnet=192.168.6.0/24" 12 | # dns=none is neccessary, because otherwise resolv.conf is created and 13 | # mounted by podman as read-only 14 | rlRun "dnsconfd_cid=\$(podman run -d --dns='none' --privileged --network dnsconfd_network:ip=192.168.6.2 dnsconfd_testing:latest)" 0 "Starting dnsconfd container" 15 | rlRun "dnsmasq_cid=\$(podman run -d --dns='none' --network dnsconfd_network:ip=192.168.6.3 localhost/dnsconfd_utilities:latest dnsmasq_entry.sh --listen-address=192.168.6.3 --address=/address.test.com/192.168.6.3)" 0 "Starting dnsmasq container" 16 | rlPhaseEnd 17 | 18 | rlPhaseStartTest 19 | rlRun "podman exec $dnsconfd_cid systemctl start network-online.target" 0 "Waiting for network setup" 20 | rlRun "podman exec $dnsconfd_cid nmcli connection mod eth0 ipv4.dns 192.168.6.3" \ 21 | 0 "Adding dns server to NM active profile" 22 | rlRun "podman exec $dnsconfd_cid nmcli connection up eth0" 0 "Bringing the connection up" 23 | # FIXME workaround of NM DAD issue 24 | rlRun "podman exec $dnsconfd_cid nmcli g reload" 25 | rlRun "podman exec $dnsconfd_cid dnsconfd status --json | jq_filter_general > status1" \ 26 | 0 "Getting status of dnsconfd" 27 | rlAssertNotDiffer status1 expected_status.json 28 | rlRun "podman exec $dnsconfd_cid getent hosts address.test.com | grep 192.168.6.3" \ 29 | 0 "Verifying correct address resolution" 30 | rlRun "podman exec $dnsconfd_cid systemctl stop dnsconfd" 0 "Stopping dnsconfd" 31 | rlRun "podman exec $dnsconfd_cid dnsconfd config nm_disable" \ 32 | 0 "disabling dnsconfd in Network Manager" 33 | sleep 2 34 | rlRun "podman exec $dnsconfd_cid getent hosts address.test.com | grep 192.168.6.3" \ 35 | 0 "Verifying correct address resolution after cleanup" 36 | rlPhaseEnd 37 | 38 | rlPhaseStartCleanup 39 | rlRun "podman exec $dnsconfd_cid journalctl -u dnsconfd" 0 "Saving dnsconfd logs" 40 | rlRun "podman exec $dnsconfd_cid journalctl -u unbound" 0 "Saving unbound logs" 41 | rlRun "podman exec $dnsconfd_cid ip route" 0 "Saving present routes" 42 | rlRun "popd" 43 | rlRun "podman stop -t 0 $dnsconfd_cid $dnsmasq_cid" 0 "Stopping containers" 44 | rlRun "podman container rm $dnsconfd_cid $dnsmasq_cid" 0 "Removing containers" 45 | rlRun "podman network rm dnsconfd_network" 0 "Removing networks" 46 | rlRun "rm -r $tmp" 0 "Remove tmp directory" 47 | rlPhaseEnd 48 | rlJournalEnd 49 | -------------------------------------------------------------------------------- /dnsconfd/configuration/syslog_option.py: -------------------------------------------------------------------------------- 1 | import re 2 | import socket 3 | from logging.handlers import SysLogHandler 4 | from typing import Optional 5 | 6 | from dnsconfd.configuration import Option 7 | 8 | 9 | class SyslogOption(Option): 10 | """ 11 | Configuration option related to Syslog logging 12 | """ 13 | network_re = r"(udp|tcp):(.+):([0-9]+)" 14 | 15 | def validate(self, value) -> bool: 16 | """ Validate that this value is a string specifying syslog destination 17 | or an empty string 18 | 19 | :param value: given value 20 | :return: True if value is valid otherwise False 21 | """ 22 | if not value or (value.startswith("unix:") and len(value) > 5): 23 | return True 24 | match_object = re.fullmatch(self.network_re, value) 25 | if match_object is None: 26 | self.lgr.error("Bad syslog destination specification %s", 27 | value) 28 | return False 29 | return True 30 | 31 | @staticmethod 32 | def parse_value(value: str) -> dict: 33 | """ Parse valid value for syslog_log option 34 | 35 | :param value: valid string value for this option 36 | :return: if unix domain is used then dict with "path" set, 37 | otherwise dict with host, port and socket_type set 38 | """ 39 | if value.startswith("unix:"): 40 | return {"path": value[5:]} 41 | match_object = re.fullmatch(SyslogOption.network_re, value) 42 | if match_object.group(1) == "udp": 43 | socket_type = socket.SOCK_DGRAM 44 | else: 45 | socket_type = socket.SOCK_STREAM 46 | host = match_object.group(2) 47 | if host.startswith("[") and host.endswith("]"): 48 | host = host[1:-1] 49 | port = int(match_object.group(3)) 50 | return {"socket_type": socket_type, "host": host, "port": port} 51 | 52 | def construct_handler(self, value: str) -> Optional[SysLogHandler]: 53 | """ Construct SysLog handler connected to specified destination 54 | 55 | :param value: string with specified syslog daemon destination 56 | either unix: or :: 57 | where transport protocol is either tcp or udp, host 58 | is ipv4, ipv6 in square brackets or hostname and port 59 | number 60 | :return: SysLogHandler if destination can be connected, otherwise 61 | None 62 | """ 63 | parsed = self.parse_value(value) 64 | try: 65 | if "path" in parsed: 66 | return SysLogHandler(address=parsed["path"]) 67 | else: 68 | return SysLogHandler(address=(parsed["host"], parsed["port"]), 69 | socktype=parsed["socket_type"]) 70 | except OSError as e: 71 | self.lgr.error("Error while trying to connect to syslog %s", 72 | e) 73 | return None 74 | -------------------------------------------------------------------------------- /unittests/dns_managers/test_unbound_manager.py: -------------------------------------------------------------------------------- 1 | from dnsconfd.dns_managers import UnboundManager 2 | from dnsconfd.network_objects import ServerDescription, DnsProtocol 3 | 4 | import pytest 5 | import socket 6 | 7 | 8 | def create_instance(): 9 | ins = UnboundManager({"dnssec_enabled": False, 10 | "listen_address": "127.0.0.1", 11 | "certification_authority": "whatever"}) 12 | ins.lgr.disabled = True 13 | setattr(ins, "_executed_commands", []) 14 | 15 | def save_command(cmd): 16 | getattr(ins, "_executed_commands").append(cmd) 17 | return True 18 | 19 | ins._execute_cmd = save_command 20 | return ins 21 | 22 | 23 | @pytest.fixture(scope="module") 24 | def instance_one(): 25 | return create_instance() 26 | 27 | 28 | @pytest.mark.parametrize("zones_to_servers, commands", [ 29 | ({".": [ServerDescription(socket.AF_INET, 30 | bytes([192, 168, 9, 3]), 31 | 53, 32 | "dummy.com")]}, 33 | ["forward_add . 192.168.9.3@53#dummy.com", 34 | "flush_zone ."]), 35 | ({".": [ServerDescription(socket.AF_INET, 36 | bytes([192, 168, 9, 3]), 37 | 53, 38 | "dummy.com")], 39 | "dummy.com": [ServerDescription(socket.AF_INET, 40 | bytes([192, 168, 10, 3]), 41 | routing_domains=["dummy.com"], 42 | protocol=DnsProtocol.DNS_PLUS_TLS)]}, 43 | ["forward_add +t dummy.com 192.168.10.3@853", 44 | "flush_zone dummy.com"]), 45 | ({".": [ServerDescription(socket.AF_INET, 46 | bytes([192, 168, 9, 3]), 47 | 53, 48 | "dummy.com")]}, 49 | ["forward_remove +i dummy.com", 50 | "flush_zone dummy.com"]), 51 | ({}, 52 | ["forward_add . 127.0.0.1", 53 | "flush_zone ."]), 54 | ({"dummy.com": [ServerDescription(socket.AF_INET, 55 | bytes([192, 168, 9, 3]), 56 | None, 57 | "dummy.com", 58 | routing_domains=["dummy.com"], 59 | protocol=DnsProtocol.DNS_PLUS_TLS)]}, 60 | ["forward_add +t dummy.com 192.168.9.3@853#dummy.com", 61 | "flush_zone dummy.com"]), 62 | ({"dummy.com": [ServerDescription(socket.AF_INET, 63 | bytes([192, 168, 9, 3]), 64 | None, 65 | routing_domains=["dummy.com"])]}, 66 | ["forward_remove +i dummy.com", 67 | "forward_add dummy.com 192.168.9.3", 68 | "flush_zone dummy.com"]) 69 | ]) 70 | def test_first_update(zones_to_servers, commands, instance_one): 71 | getattr(instance_one, "_executed_commands").clear() 72 | instance_one.update(zones_to_servers) 73 | assert getattr(instance_one, "_executed_commands") == commands 74 | -------------------------------------------------------------------------------- /distribution/com.redhat.dnsconfd.conf: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 35 | 38 | 41 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /docs/com.redhat.dnsconfd.md: -------------------------------------------------------------------------------- 1 | # com.redhat.dnsconfd 2 | 3 | version: **1.5.1** 4 | 5 | ## com.redhat.dnsconfd.Manager 6 | 7 | ### Methods 8 | 9 | - **Update**(IN aa{sv} **servers**, IN u **mode**, OUT b **all_ok**, OUT s **message**) 10 | 11 | Change forwarders configuration of the underlying caching service. 12 | 13 | Arguments are: 14 | - **servers**: array of dictionaries, each representing server that should 15 | be set as a forwarder. Allowed keys are: 16 | - address: string or bytes containing server's ip address. Only this entry is required. 17 | - port: optional, integer indicating port number that should be used. Defaulting to `53` or `853` when `dns+tls` is used as protocol. 18 | - protocol: optional, string either `dns+udp`, `dns+tcp` or `dns+tls`. Defaulting to `dns+udp`. 19 | - name: optional, server name indication. Used when `DoT` is used to verify, presence of a right certificate. Defaulting to None. 20 | - routing_domains: optional, list of strings with the domain name whose members will be resolved only by this or other servers with the same domain entry 21 | - search_domains: optional, list of strings with the domains that should be used for host-name lookup 22 | - interface: optional, string indicating if server can be used only through interface with this interface name. 23 | - dnssec: optional, boolean indicating whether this server supports dnssec or not. Defaulting to `False`. 24 | - networks: optional, list of strings representing networks whose reverse dns records must be resolved by this server 25 | - connection-uuid: optional, string uuid of the connection associated with server in NetworkManager 26 | - connection-name: optional, string name of the connection associated with server in NetworkManager 27 | - connection-object: optional, string path of the connection object associated with server in NetworkManager 28 | - priority: optional, integer indicating priority of this server, lower means higher priority 29 | - firewall_zone: optional, string indicating name of firewall zone that this server should be associated with 30 | - **mode**: Unsigned integer representing resolving mode Dnsconfd should work in. 31 | - 0 - Free, all available server can be used for resolving of all names 32 | - 1 - Global restrictive, only global servers (not bound to interface) can be used for resolving of all names. Bound servers can resolve only subdomains 33 | - 2 - Full restrictive, only global servers will be used for resolving 34 | 35 | Returns: 36 | - **all_ok** Boolean indicating whether update was successfully submitted. 37 | - **message** Additional info about operation. 38 | - **Status**(IN b **json_formatted**, OUT s **status**) 39 | 40 | Get status of dnsconfd. 41 | 42 | Arguments are: 43 | - **json_formatted**: Boolean indicating whether the output should be JSON formatted. 44 | 45 | Returns: 46 | - **status**: string indicating status of dnsconfd. 47 | 48 | - **Reload**(OUT b **all_ok**, OUT s **message**) 49 | Reapply configuration of underlying cache service. 50 | 51 | Returns: 52 | - **all_ok**: boolean indicating whether reload was successfully submitted 53 | - **message**: String with dnsconfd reply. 54 | -------------------------------------------------------------------------------- /tests/globalconfig/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k 3 | . /usr/share/beakerlib/beakerlib.sh || exit 1 4 | 5 | rlJournalStart 6 | rlPhaseStartSetup 7 | rlRun "tmp=\$(mktemp -d)" 0 "Create tmp directory" 8 | rlRun "cp ./ca_cert.pem $tmp/ca_cert.pem" 0 "Copying CA certificate" 9 | rlRun "pushd $tmp" 10 | rlRun "set -o pipefail" 11 | rlRun "podman network create dnsconfd_network --internal -d=bridge --gateway=192.168.6.1 --subnet=192.168.6.0/24" 12 | # dns=none is neccessary, because otherwise resolv.conf is created and 13 | # mounted by podman as read-only 14 | rlRun "dnsconfd_cid=\$(podman run --privileged -d --dns='none' --privileged --network dnsconfd_network:ip=192.168.6.2 dnsconfd_testing:latest)" 0 "Starting dnsconfd container" 15 | rlRun "bind_cid=\$(podman run -d --dns='none' --network dnsconfd_network:ip=192.168.6.3 localhost/dnsconfd_utilities:latest bind_entry.sh /etc/named.conf)" 0 "Starting dnsmasq container" 16 | rlPhaseEnd 17 | 18 | rlPhaseStartTest 19 | rlRun "podman exec $dnsconfd_cid systemctl start network-online.target" 20 | rlRun "podman exec $dnsconfd_cid ip route add 0.0.0.0/0 via 192.168.6.1" 0 "Add gateway so the attempts can be logged" 21 | rlRun "podman exec $dnsconfd_cid /bin/bash -c 'tcpdump -nn -i eth0 \"not host 192.168.6.3 and (port 853 or port 53 or port 453)\" > /tcpdumplog.txt' &" 0 "starting tcpdump" 22 | rlRun "podman cp ca_cert.pem $dnsconfd_cid://etc/pki/ca-trust/source/anchors/ca_cert.pem" 0 "Installing CA" 23 | rlRun "podman exec $dnsconfd_cid update-ca-trust extract" 0 "updating CA trust" 24 | rlRun "podman exec $dnsconfd_cid systemctl restart dnsconfd" 0 "restarting dnsconfd" 25 | rlRun "podman exec $dnsconfd_cid getent hosts server.example.com | grep 192.168.6.5" 1 "Verifying no result" 26 | rlRun "podman exec $dnsconfd_cid /bin/bash -c 'printf \"[global-dns-domain-*]\\nservers=dns+tls://192.168.6.3#named\\n\" >> /etc/NetworkManager/conf.d/dnsconfd.conf'" 27 | rlRun "podman exec $dnsconfd_cid nmcli g reload" 0 "Reload NM" 28 | rlRun "podman exec $dnsconfd_cid getent hosts server.example.com | grep 192.168.6.5" 0 "Verifying correct resolution" 29 | sleep 3 30 | rlRun "podman exec $dnsconfd_cid pkill tcpdump" 0 "Killing tcpdump" 31 | rlRun "podman exec $dnsconfd_cid find ./tcpdumplog.txt -size 1 | grep tcpdump" 0 "Verify no attempt to contact other DNS server was made" 32 | rlRun "podman exec $dnsconfd_cid cat /tcpdumplog.txt" 33 | rlPhaseEnd 34 | 35 | rlPhaseStartCleanup 36 | rlRun "podman exec $dnsconfd_cid journalctl -u dnsconfd" 0 "Saving dnsconfd logs" 37 | rlRun "podman exec $dnsconfd_cid journalctl -u unbound" 0 "Saving unbound logs" 38 | rlRun "podman exec $dnsconfd_cid ip route" 0 "Saving present routes" 39 | rlRun "popd" 40 | rlRun "podman stop -t 0 $dnsconfd_cid $bind_cid" 0 "Stopping containers" 41 | rlRun "podman container rm $dnsconfd_cid $bind_cid" 0 "Removing containers" 42 | rlRun "podman network rm dnsconfd_network" 0 "Removing networks" 43 | rlRun "rm -r $tmp" 0 "Remove tmp directory" 44 | rlPhaseEnd 45 | rlJournalEnd 46 | -------------------------------------------------------------------------------- /tests/logging/rsyslog.conf: -------------------------------------------------------------------------------- 1 | # rsyslog configuration file 2 | 3 | # For more information see /usr/share/doc/rsyslog-*/rsyslog_conf.html 4 | # or latest version online at http://www.rsyslog.com/doc/rsyslog_conf.html 5 | # If you experience problems, see http://www.rsyslog.com/doc/troubleshoot.html 6 | 7 | #### GLOBAL DIRECTIVES #### 8 | 9 | # Where to place auxiliary files 10 | global(workDirectory="/var/lib/rsyslog") 11 | 12 | #### MODULES #### 13 | 14 | # Use default timestamp format 15 | module(load="builtin:omfile" Template="RSYSLOG_TraditionalFileFormat") 16 | 17 | module(load="imuxsock" # provides support for local system logging (e.g. via logger command) 18 | SysSock.Use="on" 19 | SysSock.Name="/dev/newlog") 20 | 21 | # Include all config files in /etc/rsyslog.d/ 22 | include(file="/etc/rsyslog.d/*.conf" mode="optional") 23 | 24 | #module(load="imklog") # reads kernel messages (the same are read from journald) 25 | #module(load="immark") # provides --MARK-- message capability 26 | 27 | # Provides UDP syslog reception 28 | # for parameters see http://www.rsyslog.com/doc/imudp.html 29 | #module(load="imudp") # needs to be done just once 30 | #input(type="imudp" port="514") 31 | 32 | # Provides TCP syslog reception 33 | # for parameters see http://www.rsyslog.com/doc/imtcp.html 34 | #module(load="imtcp") # needs to be done just once 35 | #input(type="imtcp" port="514") 36 | 37 | #### RULES #### 38 | 39 | # Log all kernel messages to the console. 40 | # Logging much else clutters up the screen. 41 | #kern.* /dev/console 42 | 43 | # Log anything (except mail) of level info or higher. 44 | # Don't log private authentication messages! 45 | *.info;mail.none;authpriv.none;cron.none /var/log/messages 46 | 47 | # The authpriv file has restricted access. 48 | authpriv.* /var/log/secure 49 | 50 | # Log all the mail messages in one place. 51 | mail.* -/var/log/maillog 52 | 53 | 54 | # Log cron stuff 55 | cron.* /var/log/cron 56 | 57 | # Everybody gets emergency messages 58 | *.emerg :omusrmsg:* 59 | 60 | # Save news errors of level crit and higher in a special file. 61 | uucp,news.crit /var/log/spooler 62 | 63 | # Save boot messages also to boot.log 64 | local7.* /var/log/boot.log 65 | 66 | 67 | # ### sample forwarding rule ### 68 | #action(type="omfwd" 69 | # # An on-disk queue is created for this action. If the remote host is 70 | # # down, messages are spooled to disk and sent when it is up again. 71 | #queue.filename="fwdRule1" # unique name prefix for spool files 72 | #queue.maxdiskspace="1g" # 1gb space limit (use as much as possible) 73 | #queue.saveonshutdown="on" # save messages to disk on shutdown 74 | #queue.type="LinkedList" # run asynchronously 75 | #action.resumeRetryCount="-1" # infinite retries if host is down 76 | # # Remote Logging (we use TCP for reliable delivery) 77 | # # remote_host is: name/ip, e.g. 192.168.0.1, port optional e.g. 10514 78 | #Target="remote_host" Port="XXX" Protocol="tcp") 79 | -------------------------------------------------------------------------------- /tests/syslog_logging/rsyslog.conf: -------------------------------------------------------------------------------- 1 | # rsyslog configuration file 2 | 3 | # For more information see /usr/share/doc/rsyslog-*/rsyslog_conf.html 4 | # or latest version online at http://www.rsyslog.com/doc/rsyslog_conf.html 5 | # If you experience problems, see http://www.rsyslog.com/doc/troubleshoot.html 6 | 7 | #### GLOBAL DIRECTIVES #### 8 | 9 | # Where to place auxiliary files 10 | global(workDirectory="/var/lib/rsyslog") 11 | 12 | #### MODULES #### 13 | 14 | # Use default timestamp format 15 | module(load="builtin:omfile" Template="RSYSLOG_TraditionalFileFormat") 16 | 17 | module(load="imuxsock" # provides support for local system logging (e.g. via logger command) 18 | SysSock.Use="on" 19 | SysSock.Name="/dev/newlog") 20 | 21 | # Include all config files in /etc/rsyslog.d/ 22 | include(file="/etc/rsyslog.d/*.conf" mode="optional") 23 | 24 | #module(load="imklog") # reads kernel messages (the same are read from journald) 25 | #module(load="immark") # provides --MARK-- message capability 26 | 27 | # Provides UDP syslog reception 28 | # for parameters see http://www.rsyslog.com/doc/imudp.html 29 | module(load="imudp") # needs to be done just once 30 | input(type="imudp" port="514") 31 | 32 | # Provides TCP syslog reception 33 | # for parameters see http://www.rsyslog.com/doc/imtcp.html 34 | #module(load="imtcp") # needs to be done just once 35 | #input(type="imtcp" port="514") 36 | 37 | #### RULES #### 38 | 39 | # Log all kernel messages to the console. 40 | # Logging much else clutters up the screen. 41 | #kern.* /dev/console 42 | 43 | # Log anything (except mail) of level info or higher. 44 | # Don't log private authentication messages! 45 | *.info;mail.none;authpriv.none;cron.none /var/log/messages 46 | 47 | # The authpriv file has restricted access. 48 | authpriv.* /var/log/secure 49 | 50 | # Log all the mail messages in one place. 51 | mail.* -/var/log/maillog 52 | 53 | 54 | # Log cron stuff 55 | cron.* /var/log/cron 56 | 57 | # Everybody gets emergency messages 58 | *.emerg :omusrmsg:* 59 | 60 | # Save news errors of level crit and higher in a special file. 61 | uucp,news.crit /var/log/spooler 62 | 63 | # Save boot messages also to boot.log 64 | local7.* /var/log/boot.log 65 | 66 | 67 | # ### sample forwarding rule ### 68 | #action(type="omfwd" 69 | # # An on-disk queue is created for this action. If the remote host is 70 | # # down, messages are spooled to disk and sent when it is up again. 71 | #queue.filename="fwdRule1" # unique name prefix for spool files 72 | #queue.maxdiskspace="1g" # 1gb space limit (use as much as possible) 73 | #queue.saveonshutdown="on" # save messages to disk on shutdown 74 | #queue.type="LinkedList" # run asynchronously 75 | #action.resumeRetryCount="-1" # infinite retries if host is down 76 | # # Remote Logging (we use TCP for reliable delivery) 77 | # # remote_host is: name/ip, e.g. 192.168.0.1, port optional e.g. 10514 78 | #Target="remote_host" Port="XXX" Protocol="tcp") 79 | -------------------------------------------------------------------------------- /tests/dnssec/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k 3 | . /usr/share/beakerlib/beakerlib.sh || exit 1 4 | . ../dnsconfd_helper_functions.sh || exit 1 5 | ORIG_DIR=$(pwd) 6 | 7 | rlJournalStart 8 | rlPhaseStartSetup 9 | rlRun "tmp=\$(mktemp -d)" 0 "Create tmp directory" 10 | rlRun "cp root.key $tmp/root.key" 0 "Copying root key" 11 | rlRun "pushd $tmp" 12 | rlRun "set -o pipefail" 13 | rlRun "podman network create --internal dnsconfd_network -d=bridge --gateway=192.168.6.1 --subnet=192.168.6.0/24" 14 | # dns=none is neccessary, because otherwise resolv.conf is created and 15 | # mounted by podman as read-only 16 | rlRun "dnsconfd_cid=\$(podman run -d --privileged --dns='none' --network dnsconfd_network:ip=192.168.6.2 dnsconfd_testing:latest)" 0 "Starting dnsconfd container" 17 | rlRun "bind_parent_cid=\$(podman run -d --dns='none' --network dnsconfd_network:ip=192.168.6.3 localhost/dnsconfd_utilities:latest bind_entry.sh /etc/named.conf)" 0 "Starting bind container" 18 | rlPhaseEnd 19 | 20 | rlPhaseStartTest 21 | rlRun "podman exec $dnsconfd_cid /bin/bash -c 'echo \"dnssec_enabled: yes\" >> /etc/dnsconfd.conf'" 0 "Enabling dnssec" 22 | rlRun "podman cp root.key $dnsconfd_cid:/var/lib/unbound/root.key" 0 "installing root key" 23 | rlRun "podman exec $dnsconfd_cid sed -i 's/# auto-trust-anchor-file:/auto-trust-anchor-file:/' /etc/unbound/unbound.conf" 0 "setting auto trust anchor file" 24 | rlRun "podman exec $dnsconfd_cid systemctl restart dnsconfd" 0 "restarting dnsconfd" 25 | rlRun "podman exec $dnsconfd_cid nmcli connection mod eth0 ipv4.dns 192.168.6.3" 0 "Adding dns server to NM active profile" 26 | rlRun "podman exec $dnsconfd_cid nmcli connection up eth0" 0 "Bringing the connection up" 27 | # FIXME workaround of NM DAD issue 28 | rlRun "podman exec $dnsconfd_cid nmcli g reload" 29 | rlRun "podman exec $dnsconfd_cid dnsconfd status --json | jq_filter_general > status1" 0 "Getting status of dnsconfd" 30 | rlAssertNotDiffer status1 $ORIG_DIR/expected_status.json 31 | rlRun "podman exec $dnsconfd_cid getent hosts server.example.com | grep 192.168.6.5" 0 "Verifying correct address resolution" 32 | rlRun "podman exec $dnsconfd_cid getent hosts not-working.example.com | grep 192.168.6.6" 1 "Verifying correct address resolution" 33 | rlRun "podman exec $dnsconfd_cid dig not-working.example.com | grep SERVFAIL" 0 "Verifying bad validation" 34 | rlPhaseEnd 35 | 36 | rlPhaseStartCleanup 37 | rlRun "podman exec $dnsconfd_cid journalctl -u dnsconfd" 0 "Saving dnsconfd logs" 38 | rlRun "podman exec $dnsconfd_cid journalctl -u unbound" 0 "Saving unbound logs" 39 | rlRun "podman exec $dnsconfd_cid ip route" 0 "Saving present routes" 40 | rlRun "podman logs $bind_parent_cid" 0 "Saving bind logs" 41 | rlRun "popd" 42 | rlRun "podman stop -t 0 $dnsconfd_cid $bind_parent_cid" 0 "Stopping containers" 43 | rlRun "podman container rm $dnsconfd_cid $bind_parent_cid" 0 "Removing containers" 44 | rlRun "podman network rm dnsconfd_network" 0 "Removing networks" 45 | rlRun "rm -r $tmp" 0 "Remove tmp directory" 46 | rlPhaseEnd 47 | rlJournalEnd 48 | -------------------------------------------------------------------------------- /tests/bind_zones/Kcom.+008+01312.private: -------------------------------------------------------------------------------- 1 | Private-key-format: v1.3 2 | Algorithm: 8 (RSASHA256) 3 | Modulus: tHzP+I+BdWN+6fqxP8OIBVmtFiMVlK/pXV9dLtcqe/74iVhQJ85uhQBNTA36PjaiSX9C4HDurT7Vx8qhHu3i5ULuoEz0FXU6NG3Z00qy52C7+6y6FXVz19D5350SJyA9Mdfra23ikf83XdfPhYvnvXJSx7NHD8mvFsCAACIqXEumfbSKvLHQKVntxSF6fihvkmMnqgNa/8u4QUMl6EyhlzmgokXVH0miRSbs2IJT5guCljy8OSVBnvyd2J0+Y6SxoQPLNn/OU29zM0RZcPlECwKKsnm4r9HqssZePRnT8eNcsbinPF/AX5Aa9GTOCaSEgBzeRhFWnnqlWYxxOjwpGBbhE7ldJRa5i6Ny5wMvlie7bCIXZJU4bI5d1upw+fX4yq2cUAPbji3Tfsr1vDEs8cePqErW2Yyts+Iz9tl/RskuELMMFkyvybzmP78uvn6EPQrxP7SsDrMN6FIXiqN4Oj/CiaF4gGd7L7Bvf4sNW7ChOP9Zknwc4BhCmVJ6FKP3maZ36JNhNx7o9rjZ4XZlWgQErGf++RA/UqxyADtl36ldgh2krFnOyasUFIVe4u8vCDRUmcFLuX/hjLikMG2DY63mdlaRwpqaCYmFoVqBLvP2cE8vmvikVuMo30nen5h0WKc6wV2+cfEqlw8GXnXYdVDX+t9rLKw9+B8fTnYNc7E= 4 | PublicExponent: AQAB 5 | PrivateExponent: Mw2jHmIpcnUkbzb0cF702N6W8U4XSqm/zyOsjhVa9RwYXXFXqwrfhEujkcHaaUK3ASc4WZhYSzUc75jHnqIXrlYSfdGGsZMpVa9FEFlu5bgdNIGVWYCRthhste4ONncOGE1FUGwSzM1uceMb1mDOum3eMJLrpPGdz0fAbUk8xkK345LwM5Pwl+HSOhLQPWNeu//ENnkggn6zrfI6hM04YDhy0bQDJwiDGCB8mnmzFb1nwOuJKnj5aOl4FM/V2AW8IRmbn9zjFgLOiU/qJOS9dIfRh86aiVFNnCg0fAAUTbXMgJEE7TUAi4eNuFfTWDLrL/n6fcNlxwpWP1BUru5ZiPbeFQhMybD3EoiHcuqTF/Bl8OHAHDdoZKyF8JjtSdQKGbgdjRrYQnS5e5LGOGFI6eWzHwsZuQgoaTF62JE/CbcLQEF80DfCJyhQ+YoBysgSC7JEZKISmxX+4RopKioYiPHuV6V2N2GpIdfgZObptZR6UxZqQ0V5moFHsmE3fdHpSj5NjOT/mPQwBH/cMOZ0BSkxQz81jcvr5tOXTq/mxGzqaH22VNWE33X5hNz7JpvpE9kocn3UU9rgSMtly2c5eQCSbnVB63aUX3/vD1lW6rorUBlA9IiGNs83VMuY9qq8lYTEWuLwg2KYfFFr8lW2CABdkT2lPF2vCFpT6BueNOk= 6 | Prime1: 6R3a3Cl6YpnxjXGzyiYUkfWLBB3uTCSfvwAuCSg1nPxSmZ63+qhwJZGS70t6NO/OXegDVN8SgANgWYUJoPJiJ4ss71N8BImYsb/CFMecy9vOIYBzaN5oUYJQ05JBLUtPNMBPMgTDBnJWKFOSO8O8f/5GIPmdohpHbVyRxmG5odw7oAkTncVES7b7bX9K+7Cg+EGmp+pTdVPGZG2lTZbjiKInTB7Kw6nW7NVSiOe7vh3iGdoQ/too6CPefRnbdi/dZcyq+baaXJ7x6FTG7SWpTrTkrAUPHNO5JLcnWrvZuTpuQexKFRdZeHdmdHdevVE7okm5KQp2CYHdmhUyd4E05w== 7 | Prime2: xjRn6+XIEOKLGCjCEVIqH3R/C+XhdCB525Cg+BJKwCvr9tXHNCDX3dXtWI+P2ZY4gU9rUSexz+lOdBtNf9AMkTegnNizL6x2VUAKV83HxcJCm1U/3/1N4bKaKK1imuYk3uIrIx2AdA6S3lUIP20Fw6A4bjkn+lcACHgAE9gSaAFnQWb4t+bS+7n3wsTFq9PMqpCcoEe6YcDIlJo9RvFBZoqBSjvo/Y2/ouqebwdUY6RALCaT1LdOmC5QsQ0DgPeM4cfHjjvJMswjlZxbJ0/r0hS+a7htgzsKivXnERxHYaAoTHqUBGoi10Td/yu2UHuL5eHkbS5WGEL+d7k8LU1npw== 8 | Exponent1: 2mMRqbdh5AV7+ZpPaE2Mb8CsX0r693JIBVNRzVpR/6OSbj/282fgyBE8qdj3v6f4mJjGpjfkyPBgzvyHLLRlp84GZp67TDTrS3nthDIMfh6JWXFQrSnOaK3AsrQNQzWOGkke6Cj125A5jsXb9QlGClJXuISgXEBqMdXK6yKaGTyMzzwxmFg5xwTBPq9Fu8yYwHogeqZXUU8OSP8/IRT+S/48+l7ObccqhezCyWbuxwiPzNAxo88VC4Su5lvW8T2eF8RJWG7s5WAyGAlz4q6pkgZ9Q3np0oO2quK6h5H8Qj6vFCscq+2X7/dLkEhUBN+ZEkwmnoAiXH3A8JxzDumIeQ== 9 | Exponent2: HaQuunelwOiwVo+Z3k9EX2njqhrZ6a0FrFFn0VGi/jRTWJnF7cTPo6xfj3QA1lCB6MzAxuVB0U8Z3YFLyMaLaphAG9TIj2OiWsN2CIWMz8VqgqJwKAZQxGUaauTrLzEl6HM4ckryL+kSC8/5qMqcJxJp/gnsMaMbLSkNEeqpbgZvs7c7kP0jJmQ8alNVIIpPPF7eHZY8iGv1U0vxyA9CcZxbE4f8Ixc0xp+BzCbzdudUdYXba99yEI40oRXKJVpgJk/jRyEnyMIAvFoiw7FPGh7iD2gIcKy+ueNmiAeLoUz7WdynEDXzOfBhpsyZulWPqXRr3ewlEgHK3orENh4yVw== 10 | Coefficient: YhNx4FLjOTo1EM/nhqwLWD3iJOEOWUa4RnmaoHoqsTOCMpKSwYwSf1uVyUjO59wGNNMr/CTPoqwH2U/eQkk7eZ/stFe7nqWVWIAfiVUQ7NjE/mH6K4eWebXcMe7rK2Z3kf0dyYOhgcpbQM1TZNHf8Scjw0QpVUPSmQfteEr6xs3Wn90vFzFOx6Fahks5djmok7svLkgwayWXhnJ0f+X4FU8u2U24sKPA5qu81PepQ/1cf+6FtjRMcLlpcqcqAwZTtpc6GVu/lw/9aHFQc7apU4+ipr0zs6Z39KLG0lKG5Mcf9SQi0drEAEdrSqjiDfUCcG3ZKbsGWND+5YMfYa+/dw== 11 | Created: 20241213124039 12 | Publish: 20241213124039 13 | Activate: 20241213124039 14 | -------------------------------------------------------------------------------- /tests/bind_zones/Kexample.com.+008+64519.private: -------------------------------------------------------------------------------- 1 | Private-key-format: v1.3 2 | Algorithm: 8 (RSASHA256) 3 | Modulus: ra1BuyxAEprAlRrhUyPH0ZMwebnxu62ZjdzJBYlj8GiOpxZjSiMfVB7lhn68ZWArqj89YmRBUqsxgaAQxCE5e1Eangev5Cx4Yuz78RC3bciSRVdId1jh8A0NuiKaisS66HaIjIuddeDRHSagLbE7ZV0cT/gDsmxMays4YIFy0ED1qiq6kuxgMYU0FtgaFVdzfPq1lfBs+opNDH6QEcMUPhNQt1DNDk5u5f3TRA3MX9acv3s0o9Ro49XowwnoS0++7vmYpi1uB2mmaZBd79/r65h+C5S2iiUpzeH3wmOmvuNwgatWzUS2PWjO/vBCjtuEpShewW8R9D8tCJ9Em+Xqb+8u7R9HK8HS4dhsajAaiysDiMwi4cgv4m/+EoywZ0lKGZm+JaYxT3Npqt5mlKXsMGHJaFCBGi8EUWgh03DDaR6WbzaxHRH0GYnoiZ/eLZhmvVK7D9ANbZ+hWa7cbzJ8S7OVGGDpWz4HrfQKgD3nk2Pu5QmhjiLuv/OOUzXaZ6uDzW9ip0+fOKBHkF2TrOuQmyJFlYIceb5hlVwE+8mEEzfg/6rUKruuczQQrlP6v4hq0y+ssrcOrcbRXlhAaAfRFZGCgP0u3tlfnMo3lEhVxiH2kHFe5aEKho1VnbmusM99pCutGjTsAwJGbUb2HJDc7MQyle2Q2Db5hIc0V3Tq+4U= 4 | PublicExponent: AQAB 5 | PrivateExponent: Ea7Vmx8S7vypUFp08qgZTNygT48qbkzAmPxlI0EtLGnDjH5FDGQDE+eJaxDgUa9hrWspmX5SVakZ2J7ZgNP5LEsXsLC2Vz8H4C/3fus6zIdit9ipMi2Z430QwWY14fHMg0/+RdZj6SqYtU/HeJ+A8qhw8jDIVOmd5j4iTAEiFX4SWom7MVZhJ5RDt3JimtBVRouoOA9LU+myP+wVncQE/ZpYhNxJ5IOr2ug7ExoXOEgmRtYJMrJfyO1wo4W7YbT0Nb9dVsjCrn0yn7DpP5EcTi0v4tyjW/FouOOhpuh1LnOtyCYP0m/ai5TDmUVmdsZ2/PHdTp3mcBM2nJggE4IXRQnRQhPS56uQDhNAJEfLGYgpfKgj/c/8Aw0lyTqZuSsWEE19g7+Cev0UcLHpCRlIqzfgJnqe14Lk6UhDFt/ATwdMZJR6M6y4+9ebl2PvRR68uPzD2rjO0eD+rSaVsAIGg38TlRj46/IWy9DRGKSu6tAuvchP2NdMUdkzJqPfU+gUygi6PKbLjwdCevRkqgPMX+1lqRjCJFjSFgAYsGOjl3n30LLknyP+07VmLY7PrUHcXevpLp/qx6+2IYKwNPf7JmPTKRIDLyuArrmMmZ4SAdayLgQ1z0YeM/EgjfVBCFXCk9z5gnV4fUPJAZYL2ROxIRYlOm4NCpYcVsBN3SN+2Uk= 6 | Prime1: 6V+H8ki5BA18w2pR/NyP/m2yUy3Ja0OhD2mYW0oH4fLJfb7RW4UurWPi1F3HV8VcOZLv8sgYZLHNWOMYKNEU0b1coRjlPbAV3ScUe+O4DKmg52PQKvtBwmZ+sasqpdhybg+u1MSRfS4G4w7lc+tsLbgB3qq3Hum0BPCeqtmYX79vNKbTsV22X4HrhanSLVmAGETlwkNhfEfGH67EmJhUtaVdlyPFchxROXp6XRJn8cM6CJKOyRTAlyq2AgwBNKBiuVeycBElpluz1NQizYLlA4mcyd8MqZuNX45ZQE39BScYgyVJ3GYcZ1zuqZUN66c+6oRPj9Iy2dwlPZM7NB8ECw== 7 | Prime2: voQGHaK5Fet+LJTzMVj9od4p5LA32WMffpNCwLjrIA/ZRS7ugdVJsCABppNqg8Ua/AOvr2P1Xrq1r15GioDxNFeBGDzGSHZUA9dqXYBQbvHwI75/OrbCKWB5PJDM9mF+qwU2uvLnQYZtw19zyuWjoI4UpPsKnJfQgna7aNVjdeQn5ZplUPRF6T2rIJ4unicArY7F9bDymPgeY7Lp2/r/FPg83gDil0Zik9+5xVfa6x/Rg4VDA71TA8sidgH6HZbQMeiUSwPyl9731eDAVV4s00ebjV3MfNzzuyYdzx/7lIPBKC8IRUdCmFGDxDoI6H6r6KGXmctOxFvtD81AhTCorw== 8 | Exponent1: soU+hGt3BI+gsgfh4fGDQRj/AbwTyTb5vMWFI8g00XYdBlDy6/SsaTzwpo16UT0LOIube/fvGRAeSnGl6ItQRsV5V06pBhBuGTes5ryi7STRjk//TPHZMvGe1yBdxnIVzvW2QtJ/jOepowWhJpSfszWAUKn83Ovfpqu+ZGmBszTIx9kaNSK/wL2swhnPSpudbnM94uYSa7Sn7VKO10AoBLAUMOrPPmRFChgUBKBw3TL/cNFT4qQ6Uyj8BALU5UIPY0KfoDStvV2G6jbAzL7lm1golRBIKnJwqflFcvh1pfxrNt9Oage+kJ85foYkGPFeIp3GEvmzpo5N+pVnA476Uw== 9 | Exponent2: nSG8/ZJpf2fEoDaVwjy4rFnVSbYByj1UC4yfwN6DpuULeWE0/EaTST2MvvvVHStjjznnHAygounx0ds66R9iUZ5ebkQp8jgOIUD5jHa5YFgRjRmgTCfSSlg0hjyToB5XX+yj8FtJWyTpwPsoQM9YPqMQ6eXYIcGhCwmsltFxABoWweuu5q8iPjZLv1JX9r8KcxtPsM2puXrjba1x7qq82mnHof8u5D/8LCSZTuegOs76ebReymXLY1SWbqhAx0jNHGzManauDo6q8G83kvFinTvxUw5rCw0dxVyxt1SUpjBpDqCD/MfCaGjK+fw3vrJDTVKB/CnQJGoBQ0gxj+jLJw== 10 | Coefficient: OqyfBxkWLY9cbIhWZAiY2kP1QseuZEni9gs7cehLdzcLgzvZUwJOWLWdiwM+xY+9Bi1B4cxNXQ38g9rbV8Q+7kjWkZHWmBUusSCR5P+y+bRl3BOjcsXVPEUPIPUR7Zj5jM+7jj1/0qu1GtIzDeQdXCAzsTezH4cBKQYuWQ87Zx59fWExqHwAbOkpSDUJKRSDegX3g9Rzlfn2sWQNF5II7sf+lpuDpWZJx1OQtsgik1OTlnFZJ2MlZBZYd5q9ig84atFtMv28hkIGcljS5Y5eOL1trNI7mgF4SNIQqGR09qxTVU0r5WolDtQ6brx00QymYUxIqeNJeY4e98Ek2pb++g== 11 | Created: 20241213123823 12 | Publish: 20241213123823 13 | Activate: 20241213123823 14 | -------------------------------------------------------------------------------- /tests/listen_address/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k 3 | . /usr/share/beakerlib/beakerlib.sh || exit 1 4 | . ../dnsconfd_helper_functions.sh || exit 1 5 | ORIG_DIR=$(pwd) 6 | 7 | rlJournalStart 8 | rlPhaseStartSetup 9 | rlRun "tmp=\$(mktemp -d)" 0 "Create tmp directory" 10 | rlRun "pushd $tmp" 11 | rlRun "set -o pipefail" 12 | rlRun "podman network create dnsconfd_network --internal -d=bridge --gateway=192.168.6.1 --subnet=192.168.6.0/24" 13 | # dns=none is neccessary, because otherwise resolv.conf is created and 14 | # mounted by podman as read-only 15 | rlRun "dnsconfd_cid=\$(podman run -d --privileged --dns='none' --network dnsconfd_network:ip=192.168.6.2 dnsconfd_testing:latest)" 0 "Starting dnsconfd container" 16 | rlRun "dnsmasq_cid=\$(podman run -d --dns='none' --network dnsconfd_network:ip=192.168.6.3 localhost/dnsconfd_utilities:latest dnsmasq_entry.sh --listen-address=192.168.6.3 --address=/address.test.com/192.168.6.3)" 0 "Starting dnsmasq container" 17 | rlPhaseEnd 18 | 19 | rlPhaseStartTest 20 | rlRun "podman exec $dnsconfd_cid /bin/bash -c 'echo listen_address: \"127.0.0.64\" >> /etc/dnsconfd.conf'" 0 "Change listen_address" 21 | rlRun "podman exec $dnsconfd_cid systemctl restart dnsconfd" 22 | rlRun "podman exec $dnsconfd_cid nmcli connection mod eth0 ipv4.dns 192.168.6.3" 0 "Adding dns server to NM active profile" 23 | rlRun "podman exec $dnsconfd_cid nmcli con up eth0" 24 | # FIXME workaround of NM DAD issue 25 | rlRun "podman exec $dnsconfd_cid nmcli g reload" 26 | rlRun "podman exec $dnsconfd_cid dnsconfd status --json | jq_filter_general > status1" 0 "Getting status of dnsconfd" 27 | rlAssertNotDiffer status1 $ORIG_DIR/expected_status.json 28 | rlRun "podman exec $dnsconfd_cid getent hosts address.test.com | grep 192.168.6.3" 0 "Verifying correct address resolution" 29 | rlRun "podman exec $dnsconfd_cid cat /etc/resolv.conf | grep '127.0.0.64'" 0 "Verifying correct listening address" 30 | rlRun "podman exec $dnsconfd_cid /bin/bash -c 'echo LISTEN_ADDRESS=\"127.0.0.32\" >> /etc/sysconfig/dnsconfd'" 0 "Setting service env file" 31 | rlRun "podman exec $dnsconfd_cid systemctl restart dnsconfd" 32 | rlRun "podman exec $dnsconfd_cid nmcli con up eth0" 33 | # FIXME workaround of NM DAD issue 34 | rlRun "podman exec $dnsconfd_cid nmcli g reload" 35 | rlRun "podman exec $dnsconfd_cid getent hosts address.test.com | grep 192.168.6.3" 0 "Verifying correct address resolution" 36 | rlRun "podman exec $dnsconfd_cid cat /etc/resolv.conf | grep '127.0.0.32'" 0 "Verifying correct listening address" 37 | rlPhaseEnd 38 | 39 | rlPhaseStartCleanup 40 | rlRun "podman exec $dnsconfd_cid journalctl -u dnsconfd" 0 "Saving dnsconfd logs" 41 | rlRun "podman exec $dnsconfd_cid journalctl -u unbound" 0 "Saving unbound logs" 42 | rlRun "podman exec $dnsconfd_cid ip route" 0 "Saving present routes" 43 | rlRun "popd" 44 | rlRun "podman stop -t 0 $dnsconfd_cid $dnsmasq_cid" 0 "Stopping containers" 45 | rlRun "podman container rm $dnsconfd_cid $dnsmasq_cid" 0 "Removing containers" 46 | rlRun "podman network rm dnsconfd_network" 0 "Removing networks" 47 | rlRun "rm -r $tmp" 0 "Remove tmp directory" 48 | rlPhaseEnd 49 | rlJournalEnd 50 | -------------------------------------------------------------------------------- /tests/named_certs/ca_private_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDODk0+ACG1FjvZ 3 | zGOdn+Afjz2ewTa8Uj6KHjbQxPbt3RPJUp+SmgGdsCWCtQNjw7snLpI3B6bm19Wx 4 | ka9GiC3a5PBJ63IGYIDhyLAEcWi5WfEjXyu3RX33XwSRfnEtcQH5GM6z8YguHrx1 5 | jwo55dL/CYE7yuYF+whIXd8efhE7a+4DQHpM8U4Abv4Zl2WEwuCW0I/+odvyDYs3 6 | SO+GjItBGFiotJd4RXtW8ehFPPNmYirK2tTO0QX6Ue3o8TDjM9SjIbz776NfzgDp 7 | QTp9Nz+QfZOlHyyLc7fW0xQvnXv6kVQ2+pZFll4T/Oxv2fjpPfxxpnHEmJCycqiD 8 | oTAxq23wnwMLGsA27VA8xJGttNo5dIAd1lRUUP74xZvLp6eYpxap8eHNvpsebNgk 9 | m4PBrdSdn2U0OB4CmCJTPOdqftZKi1phycvo/5VQSQzcDI+yOpI0RnxvLw5rh2Dw 10 | nmwYewd7raJ6WOrjgvpKRdhIklvcC6eaV2lI/uOggPgPWKdG0WCJ0JdxTeSrhvkY 11 | fWfPzAR1IYfNZd3eMOBrHI5feNHQ+3hKkKdkN26m+An9Z6GQoCrej6eSalU98zJp 12 | eOg9euGe2bJ1Q592sdhdcoV/OrmbNg3vJTDxXeiV5NxRWcMZeF59hQWm80DTM+Lz 13 | oS974NCls954W791l3e3u1eR96J2eQIDAQABAoICAAJ/dE1Wu3yKSBWKMjXHqalp 14 | nKfTTt5Y+bgF/lMzpLcqNYp8nAwvHgB7Jsnsd2hYPR6a2cv9OvdEK/Y0Dl2tZQST 15 | lHv0P4H8iD9vGyl4oE9+kRXlJNQQTXg9gII3gqLNgoZnorTWI25EsjM+IEkmpDMc 16 | 2pepbGEA7lR7P9XLAIWPAm1WFM115OShiSbGry+ScbNzqd/ejC/QB81MJEGGLAzR 17 | ATJ4BaM1e2roxzsp+PI3foOORCNm2lrSxK6s2CipmOT/3GkU76RHtzrcpFtUJhWn 18 | 3LhKa2lcMMuzwW7uKqyKomHWvJIxd2iTCbY1kccDuM7+DgBskDTQ6ez2O/h0LAKy 19 | bMwVy7jzB8zYUmSqElLKzLtljIYHW0t6kOFnRbMGeMWuzP9tu3lETGd3T1i/lLu7 20 | E4d69QrbT1kMElCw0oLnWfXvSwxHaD7ZALnxeQdZSVE9QtEqKvxZam/gljLltjPf 21 | +mtT6MTvT3ZlK0VkjvX+pmdi1qmzXR9wBsyf8QRp30etE8bpBhMwZ9Gnmt+Yg3Tb 22 | pNsbiFpgvHqqIcCj7wegLNe/kqdF2/cy0aIrJ+g+n+leDZzEjvM+BRMYVOY0OezU 23 | CFaoZ/zPmQ3z47RZnV7ydVahag2DftA+3WFGosExTxfzOBFPzbQ40/eC2pQ+tKxQ 24 | 9RS+k57Gav4SFarxJMgxAoIBAQD5/FVywUe5Xj/M0VA4sq1ocwyG58ko3Wcpj4vy 25 | MwhGSueaQxAQUa0DvcNjBAK4Rs8S3C+iXErWEQMB1kE1oIGL6oAZeDaAoWewybc1 26 | BsPgBVCzm6YwWgPlTEirUxp4uTLMlL9TrxiyXd2llze1IrKSgBbxANiPqYG6qYVm 27 | 37eXzR3PTx+QBjqUxcgcCRtoa/albLCJhce/a1fET/OM6cj/agAQWxHI03d+zFUW 28 | xb59lYjpZgtlbn4X9jpnZbkXge+8kWCtI9OpcGNeWo97MYgehMqmCVQ3Qedgk5RH 29 | EH9wPijudIDXKXQAMHRxWCpz6/JOpwH02UQyg3nfd9Uyh/jJAoIBAQDTA2dImLij 30 | J+GeiYXla8GotxbU+YIvsXwsGqbau+jeo55IT0AOlc/zonbnAf1OvNHD+CgFfy7i 31 | Q+VsX2SBai60za4F4pju5Mn4RuuwYRlS6TM/S1xJZpEZOk2VK1Z2tPD/ySTqYGAk 32 | 0FhIci+0p980CphA61VYT7vGPm6jZB30plnU2z9s2/FElPUvsmS6C2JnoQNcGFCG 33 | C7KEuaQvW/LP9eE2T3Wy78C1Z5r792Pr40brLgy+gQPiRpsgftcbkYFKNv97uyrd 34 | zrZcZ4vfynz5LkV1HrH1r+90yjsFPA/obbCoxHRVM64H9eUp/Cer8WiOIglDG5+0 35 | zuuLRBc3gRgxAoIBAQDaCT1aFryBMHRDJ3lpymY3CMmvTLEGRH27ISm1uM8JyEFT 36 | KhTzttlJvxSQ4ymgIppv375oRUk8hp/x1TcRGAqFx6WtEU2wSZcP+hAiXuEvHlOy 37 | JBsCZzCoqS1kyNn428cz6rUpvzmyMO6mhEshYL8Ryki4Mb2xJ+4vqbXh8VTHQS8z 38 | 5tYnn1cu9YbA9SyDmk8JH9CmUhnTmkN1xSovCKW4KHMf0N6lI9RAsuWwNA8ep/M/ 39 | ZzKfaIzwR2HPV0jl+P3poX8J5IqzaYQyApjMoXoQ7E94HADpJUEy2eVlSj1s37qB 40 | qPnLMKutkpWtWnHEo9G2yjGJpoq16Di/MVyxcykJAoIBAQCXKUT/+IesOZGi5JmK 41 | tBrTJfWxM9xTFi4B2kXVQ++aLlPhMQSObju+KJBNBFvV3+XVIRxqc6W+aS0c6Wky 42 | XEKBOyaDCMTNvhABT6zfeW+OuYgAu5es7VDcZavWRGl4OD68vfc3/zpgpO/ZVhNe 43 | szNuMHjJaMyGqve1GFxhqALdk52eokFZVmYL3zmVpZIKxMUFv46Mls54eEC2W9aG 44 | JrRWzak8IsgKGz5NtZ6NCbgG75WKPD7c6cdCfZn7OWIXWbDo3WU/2eDnbIGuyG6n 45 | LoNAbilLsWWCvzomzAhjw5cRxiJbhABiWNc+1KQJ45z3y8Q+rZs8+7j46ZJK/cgz 46 | 9sLBAoIBAF6kEDrva7J6rsrwVUh/n4nNtKx5bvpkWmUVuQ3CXbIjYXx4SxBpijp0 47 | r3V6IpDZkGtyoU0b0sk+259662t0NUh+FReHNCg6mwlxsJ1EsyLNCGZ36/qT0e5F 48 | adUiPzh49aRdMifbvwrRXPah0ZntqqiuyaJ8Kk9OzbDeZuxcchBvaWxraLqj9TpS 49 | ax6PYbNm2pFtBosJyg3zgiBaBWMpU9MLUPsxfEXnupVAxAk5f58+R3dUEdZUlPUq 50 | BCNfhab81VeuoOxIP6RCMhNhnQS/ZL+dhLy5VH05G1xNvVmNivNBArdYMxsndSZ6 51 | 3F/PsHqVvBljgRXguiVs/oe14b3kOr4= 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /tests/named_certs/my_private_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQC1C61hmqkU9Y1t 3 | wFCf5qFvyu8ju7KSruyo42st+9a8jlQN5lq6VSunzeOuLCNTfaREtJkMFgOrUoJI 4 | gIKNbecuZSxyOAQXNBtsbkGAMBuDZwGZHEEpghuxrXEpVm2gRSMJsU7cZP/bPDIS 5 | FFQAlW5/SflmJ/oKh0SckDyR4G4Iir/jNeyFdry8yMD1cAN09adBkfj13gGXHMEN 6 | NZHEWyj1JDMI3zWsR9rmn+dLw/RJBm/TMoYr24hehwuZTrw7GO+ElgARgm990yOl 7 | NNcliWUoB02tBrLnoWVIVsigV2+4kqSiNUOU5O7yAbvuGWBLejywPRPq91Kzyff+ 8 | DUvnlu4bfsq5IRdb2TLuUKC2CbFTDAg1F2J8D2SpNH2B+/WVXH7nQj9E8adOf/JF 9 | Ca3rXHqoi/x7EffsmRuNxkmVOKhExBhM2sy6JIz4znTUgowD+TsmWRHC2Q571vQa 10 | 9onNUP48FRwBhG1NVzv2hHHaEPqDMEQgk8gHpNVLhLO8QVXJfxUnLPobWxRnLZKZ 11 | 0J65chTR4UW6uP/E3YRPH8xejJgWL2RSIJvicEQ7XDbKlZuIVz811XQmfCUDmwUG 12 | 6Xwuahw6w3ZBxYCl4hHXwvVqyyxFuQPDxHJi22dAl43Bs7yyZzDM0Ow1kBbLDkmJ 13 | ubblJlGnAPNo1MSHYjLtOFKGanYTywIDAQABAoICAALEC1DtbXsZVjGViN7TRZv2 14 | tj0yOl++YTKzDM3Lfcz04z5R/LrMex9cYr9WMBwOhmIRXKu3GLqZ7e6vUBTVKve5 15 | dWRunNv+fx5oLySMmmC9Br3EYyWsjsyT2CdO4lYScg5NWeV7DJBH02wVVBIRQXpu 16 | /a2VpqF6rOQdlwaZI3R/YwKtybaZCSTMC7nno4pnB/r8TqmCYhvhNJjY9GAmfgVz 17 | UOIaRUmTKZ5aujB7tdAgZCfyiZVIayPNVRapB1UVce/8cYXH00byv4+5F1g+Q0Ac 18 | 12gukTZgSNnjhHjP1Bn+o7BRCrvZ8w3Z5LahMNT0RISwTU/r0TWPR2OfFD/uG+6x 19 | VuYCTZ3foWG3y6YWImaw270a4nImEPo3RHwzvf0GjOd7mbzkVS3Fgst4MutFeoa5 20 | 72Kn/e1CBmRZZgjiqjaqgmfe4kkqQNiMbghZkm9dmfD7YmNkrsnSpBG4A7QetGSW 21 | IjCdAoep+rn58Q1CdBVMCrDHasw8m8wb1xmyfTciXFyDucCf4TOKkt5Byb/ps7h6 22 | t76QwxsICa+9Jee9p/b1LJMVqxFM2T1PKbG2tClttmPL+dznOAgbP19jAdRTYcjt 23 | fjnT68JgqjdTzgFyyp2OR24I6UNCcdGmnDhMZ7xl63e/6nOWgKnfhCguqx9seycN 24 | yGuJeAzPvGy7gil/1wpJAoIBAQD59dO0fzp3YHKjeGaTE7OJsMkI6GvvBw/5w8zy 25 | mhRJu6ts/sydvk27ECYnjWEX+Eckzawp34Q6CRAIQby3DbnCodkOYkWNeWukHBYa 26 | zKJK0f+cHiCZBl0aBB5iFkVqbvG6qFIJkl1AFnVk/9XcDJZj7wz+HXSAcC/+GHas 27 | vqNIK2XLb4hqTNaN2SuYpkXQeztGRnS4CplPklazM09Nq0XwKJKa5pHqiyBxvfef 28 | qQeRyC8CcSxCpALW4we6zTT+J5WHew8bR7e+yIVKSNKUbhRx2rO98fr7BzWnrpim 29 | Zc4We1oeE5BpALrKNPTY7A0AHi99O2iwEJsx38K+q+K20tozAoIBAQC5a5EQ1xMu 30 | +UxpOKkZyQIJATk8gtCWvfe0+rBnWqyZHVRlJrrvTHJtPEZIuOzAtMcVsvCeDPW6 31 | ILV1mrbFMV42nLFQOw/H8GCe7ChnF1FDWhxa03khw2i9nvepUNa7xxXQACd16nrJ 32 | FnO0uBvNMlZElYYhX1sRqjvi0HDqFkDddF+iL5ikqRisAQ6fDAWlIPzVDJu58prW 33 | 3MbvIFbQOqjyHdw4Y3YnMH2d23hh0imq1fb2B1l9Hky1TWWrL0f0aZuHvRfkAl5o 34 | Mb02ffilUef3FO1RxZ3JOz+VarLC8iHDrXpqd3mL2rf6RvEEY6dXNUf4zjyG1uGL 35 | EFDDVw+aqfgJAoIBAQD4xDdWQ+kkNdDh8Enlxo3AUzlArE//K8AyizPFnqLiXuxV 36 | JaDuvR8PNRtD8ejXujjT3/2gDtvCBpL2JLZ0WCywD/O95P/jtRvz0CAPu+kpHaaO 37 | 8Uzv/u1Znw+9/vxG2POrGSnMbOZxieh8BEILJlvmSVtc7GOuD/kzoZU6huBqSwac 38 | WPwjDyXZNnG1EoYY3ww2/JfdMm8ySioPXtlmKzcHtNlzYFWIX76CdNWlCMyHwftH 39 | Kuspx6Ery/c9ak17RFoE4+w88jtknJxLOf6ZypR+W3LXb6ShgKNdpt41fMyGg21E 40 | 0aO/XQKJi/rCiOrHW0NYF3AxCdXq5Q8kRFz2JxMRAoIBAQCrlc41nkIjWxIJ4SQj 41 | N28JtDcqNwgeJweeU8qAqllEi+64eEHPBphxW7DSxUZaAjCldOTT7bxLlM83WIfA 42 | LbI4qYIwc6dj558SEgpFdD+AK1hH+KCEzRcVOpGG/sboGBCoXiwmI2miwoMqfqFD 43 | n0xTxWbNZTeaPkWS3D9RcGxwQqvpI1CHN/Ab5BKKvg5PRBqUcUl+pvIA2WfCi9Oq 44 | eE41V8qd5/TDyUzFkv5wz5I9hCk4fY6jiTGFKW1nH6bfmAcUcrk0B7kjhLvLPIGn 45 | Qwd9D8GZxV0BhjGN7KImYvk54kSBV7SD5lAQbCvHWwzVV/oVVYyPXzRygxOp4NwQ 46 | zS85AoIBAEGH/fEuaMASKstVUy4WsnFLlBGDvYo8Gtf4nH6xNktxpXXTCU3HfJTi 47 | cu5OSHQEV4kc4dL9VvJKQ+0Tj1bP1aANdvbiC9mX4UvcLW66pJCL21XgQ3Dt+Dyp 48 | lBtTDVYHP44LNBMTxLHFYZS+IaQ70ZPnAriyY3RIMSJyVQ90jpGp9NwQ/ys2Gzcq 49 | 899bYnMfneAbeON+f87zVo5N4TAIjw8seRec+QNDitzhLa7c+mL7OOR16kTSkxwW 50 | BkIMBYhu1g9V2AD35LlJ3nYxV7cBHWiT0q9Xpha3Zwx5Iq89zoftvnlWgZFHRAV4 51 | 7lqa4jK60+buvH+gvjbuBH5Ycf9Pbz8= 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /tests/two-interfaces/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k 3 | . /usr/share/beakerlib/beakerlib.sh || exit 1 4 | . ../dnsconfd_helper_functions.sh || exit 1 5 | ORIG_DIR=$(pwd) 6 | 7 | rlJournalStart 8 | rlPhaseStartSetup 9 | rlRun "tmp=\$(mktemp -d)" 0 "Create tmp directory" 10 | rlRun "pushd $tmp" 11 | rlRun "set -o pipefail" 12 | rlRun "podman network create dnsconfd_network --internal -d=bridge --gateway=192.168.6.1 --subnet=192.168.6.0/24" 13 | rlRun "podman network create dnsconfd_network2 --internal -d=bridge --gateway=192.168.7.1 --subnet=192.168.7.0/24" 14 | # dns=none is neccessary, because otherwise resolv.conf is created and 15 | # mounted by podman as read-only 16 | rlRun "dnsconfd_cid=\$(podman run --privileged -d --dns='none' --network dnsconfd_network:interface_name=eth0,ip=192.168.6.2 --network dnsconfd_network2:interface_name=eth1,ip=192.168.7.2\ 17 | dnsconfd_testing:latest)" 0 "Starting dnsconfd container" 18 | rlRun "dnsmasq1_cid=\$(podman run -d --dns='none' --network dnsconfd_network:ip=192.168.6.3 localhost/dnsconfd_utilities:latest\ 19 | dnsmasq_entry.sh --listen-address=192.168.6.3 --address=/first-address.test.com/192.168.6.3)" 0 "Starting first dnsmasq container" 20 | rlRun "dnsmasq2_cid=\$(podman run -d --dns='none' --network dnsconfd_network2:ip=192.168.7.3 localhost/dnsconfd_utilities:latest\ 21 | dnsmasq_entry.sh --listen-address=192.168.7.3 --address=/second-address.test.com/192.168.7.3)" 0 "Starting second dnsmasq container" 22 | rlPhaseEnd 23 | 24 | rlPhaseStartTest 25 | rlRun "podman exec $dnsconfd_cid systemctl start network-online.target" 26 | rlRun "podman exec $dnsconfd_cid nmcli connection mod eth0 ipv4.dns 192.168.6.3" 0 "Adding dns server to the first NM active profile" 27 | rlRun "podman exec $dnsconfd_cid nmcli connection mod eth1 ipv4.dns 192.168.7.3" 0 "Adding dns server to the second NM active profile" 28 | rlRun "podman exec $dnsconfd_cid nmcli con up eth0" 29 | rlRun "podman exec $dnsconfd_cid nmcli con up eth1" 30 | # FIXME workaround of NM DAD issue 31 | rlRun "podman exec $dnsconfd_cid nmcli g reload" 32 | rlRun "podman exec $dnsconfd_cid dnsconfd status --json | jq_filter_general > status1" 0 "Getting status of dnsconfd" 33 | rlAssertNotDiffer status1 $ORIG_DIR/expected_status.json 34 | rlRun "podman exec $dnsconfd_cid getent hosts first-address.test.com | grep 192.168.6.3" 0 "Verifying correct address resolution" 35 | rlRun "podman exec $dnsconfd_cid getent hosts second-address.test.com | grep 192.168.7.3" 0 "Verifying correct address resolution" 36 | rlPhaseEnd 37 | 38 | rlPhaseStartCleanup 39 | rlRun "podman exec $dnsconfd_cid journalctl -u dnsconfd" 0 "Saving dnsconfd logs" 40 | rlRun "podman exec $dnsconfd_cid journalctl -u unbound" 0 "Saving unbound logs" 41 | rlRun "podman exec $dnsconfd_cid ip route" 0 "Saving present routes" 42 | rlRun "popd" 43 | rlRun "podman stop -t 0 $dnsconfd_cid $dnsmasq1_cid $dnsmasq2_cid" 0 "Stopping containers" 44 | rlRun "podman container rm $dnsconfd_cid $dnsmasq1_cid $dnsmasq2_cid" 0 "Removing containers" 45 | rlRun "podman network rm dnsconfd_network dnsconfd_network2" 0 "Removing networks" 46 | rlRun "rm -r $tmp" 0 "Remove tmp directory" 47 | rlPhaseEnd 48 | rlJournalEnd 49 | --------------------------------------------------------------------------------