6 Commits

Author SHA1 Message Date
Daniel Akulenok
68a7b62305 chore: update molecule configuration
- Update prepare.yml with test setup
- Update molecule.yml with test infrastructure configuration
2026-01-28 23:03:41 +01:00
Daniel Akulenok
dae9cb60f5 test: add bind9 forwarding DNS server test case
- Create converge.yml with forwarding DNS configuration
- Configure global forwarders with Google and Cloudflare DNS
- Configure forward-only zone for internal.example with TLS
- Create verify.yml with comprehensive test validation
- Test BIND9 installation, service status, and configuration files
- Verify forwarders and forward zones are properly configured
- Test actual DNS resolution via forwarders
2026-01-28 23:03:30 +01:00
Daniel Akulenok
d075e3ec17 docs: update README.md with port/tls parameter patterns
- Add clarification on different parameter combinations (port/dscp vs port/tls)
- Replace generic 'IP_PORT_DSCP_OPTION' with 'ADDRESS_PORT_TLS_OPTION' example
- Update all configuration examples to show port/tls parameters
- Document usage of forwarders with TLS support
- Improve documentation of flexible configuration formats
2026-01-28 23:03:25 +01:00
Daniel Akulenok
e8f84fce0b docs: update CONFIGURATION_GRAMMAR.md for forwarders port/tls support
- Add tls parameter to forwarders grammar in options section
- Add tls parameter to forwarders grammar in zone section
- Update options and zone examples to demonstrate tls usage
- Rename 'Address with Port/DSCP' section to 'Address with Port/TLS'
- Update all data type examples to show port/tls patterns instead of port/dscp
- Document global and per-address port/tls configuration options
2026-01-28 23:03:19 +01:00
Daniel Akulenok
3d2919721b feat: use parent_address_port_tls macro for forwarders
- Update named.conf.options.j2 to use parent_address_port_tls for forwarders
- Update named.conf.zone.j2 to use parent_address_port_tls for forwarders
- Enables support for per-address and global port/tls parameters
2026-01-28 23:03:07 +01:00
Daniel Akulenok
112ba5f7ca feat: implement list_address_port_tls and parent_address_port_tls macros
- Add list_address_port_tls macro for rendering address lists with port and tls parameters
- Add parent_address_port_tls macro for parent statements with global port/tls
- Follow existing naming pattern with separate list_ and parent_ macros
- Supports forwarders, primaries, and similar blocks with port/tls grammar
2026-01-28 23:02:59 +01:00
9 changed files with 181 additions and 32 deletions

View File

@@ -458,6 +458,7 @@ options:
- <address> - <address>
- address: <address> - address: <address>
port: <port> port: <port>
tls: <tls_name>
# DNSSEC # DNSSEC
dnssec_enable: <bool> # DEPRECATED in 9.15+ dnssec_enable: <bool> # DEPRECATED in 9.15+
@@ -593,7 +594,8 @@ options:
forwarders: forwarders:
- 1.1.1.1 - 1.1.1.1
- 8.8.8.8 - address: 8.8.8.8
tls: dot-tls
dnssec_validation: auto dnssec_validation: auto
@@ -917,6 +919,7 @@ zones:
- <address> - <address>
- address: <address> - address: <address>
port: <port> port: <port>
tls: <tls_name>
# DNSSEC # DNSSEC
dnssec_policy: <policy_name> # DNSSEC policy to use dnssec_policy: <policy_name> # DNSSEC policy to use
@@ -1017,7 +1020,8 @@ zones:
forward: only forward: only
forwarders: forwarders:
- 10.0.0.1 - 10.0.0.1
- 10.0.0.2 - address: 10.0.0.2
tls: internal-tls
``` ```
--- ---
@@ -1079,9 +1083,9 @@ addresses:
- 10.0.0.0/8 - 10.0.0.0/8
``` ```
### Address with Port/DSCP ### Address with Port/TLS
For options accepting `address [port X] [dscp Y]`: For options accepting `address [port X] [tls Y]` (e.g., `forwarders`):
```yaml ```yaml
# Simple list # Simple list
@@ -1089,27 +1093,28 @@ forwarders:
- 1.1.1.1 - 1.1.1.1
- 8.8.8.8 - 8.8.8.8
# With source port/dscp # With global port/tls
forwarders: forwarders:
port: 5353 port: 853
dscp: 46 tls: dot-tls
addresses: addresses:
- 1.1.1.1 - 1.1.1.1
- 8.8.8.8 - 8.8.8.8
# Per-address port/dscp # Per-address port/tls
forwarders: forwarders:
- address: 1.1.1.1 - address: 1.1.1.1
port: 53 port: 53
- address: 8.8.8.8 - address: 8.8.8.8
port: 5353 port: 853
dscp: 46 tls: cloudflare-tls
# Mixed format # Mixed format
forwarders: forwarders:
- 1.1.1.1 - 1.1.1.1
- address: 8.8.8.8 - address: 8.8.8.8
port: 5353 port: 853
tls: dot-tls
``` ```
### Address with Key/TLS ### Address with Key/TLS

View File

@@ -126,38 +126,43 @@ Simple options are defined just as that.
``` ```
Some options have several optional parameters. For those, a somewhat flexible Some options have several optional parameters. For those, a somewhat flexible
configuration format has been created configuration format has been created. Common patterns include:
- **Address with Port/DSCP**: Used by options like `primaries`, `parental_agents` (e.g., `address [ port <port> ] [ dscp <dscp> ]`)
- **Address with Port/TLS**: Used by options like `forwarders` (e.g., `address [ port <port> ] [ tls <tls> ]`)
``` ```
IP_PORT_DSCP_OPTION: # Any option that is defined as one of: ADDRESS_PORT_TLS_OPTION: # Example: forwarders option
# <option> [ port <port> ] [ dscp <dscp> ] { <address> [ port <port> ] [ dscp <dscp> ]; ... } # <option> [ port <port> ] [ tls <tls> ] { <address> [ port <port> ] [ tls <tls> ]; ... }
# <option> [ port <port> ] [ dscp <dscp> ] { <address> [ port <port> ] [ key <key> ] [ tls <tls> ]; ... }
# has a few optional syntaxes # has a few optional syntaxes
# Example 1: Simple address list # Example 1: Simple address list
- ADDRESS1 - ADDRESS1
- ADDRESS2 - ADDRESS2
# Example 2: To define source port/dscp, use 'addresses' sub-element # Example 2: To define global port/tls, use 'addresses' sub-element
[ port: PORT ] [ port: PORT ]
[ dscp: DSCP ] [ tls: TLS_NAME ]
addresses: addresses:
- ADDRESS1 - ADDRESS1
- ADDRESS2 - ADDRESS2
- 127.0.0.1 - 127.0.0.1
# Example 3: To define target port/dscp, use 'addresses' as a list of dicts # Example 3: To define per-address port/tls, use 'addresses' as a list of dicts
addresses: addresses:
- address: ADDRESS - address: ADDRESS
[ port: PORT ] [ port: PORT ]
[ dscp: DSCP ] [ tls: TLS_NAME ]
- address: 127.0.0.1 - address: 127.0.0.1
port: 53 port: 53
- address: 127.0.0.1 - address: 127.0.0.1
dscp: 42 port: 853
- address: 127.0.0.1 tls: dot-tls
port: 5353 - address: 8.8.8.8
dscp: 42 port: 853
tls: google-tls
# Example 4: The various formats can be mixed and matched within the main element # Example 4: The various formats can be mixed and matched within the main element
- ADDRESS1 - ADDRESS1
- address: ADDRESS2 - address: ADDRESS2
port: PORT port: PORT
tls: TLS_NAME
``` ```

View File

@@ -5,3 +5,37 @@
- name: Include bind9 role - name: Include bind9 role
ansible.builtin.include_role: ansible.builtin.include_role:
name: ../../../ansible-bind9-role name: ../../../ansible-bind9-role
vars:
bind9_host_config:
- name: named.conf.options
options:
directory: "{{ bind9_working_directory }}"
recursion: true
allow_query:
- any
allow_recursion:
- 10.0.0.0/8
- 192.168.0.0/16
- 172.16.0.0/12
- localhost
- localnets
forwarders:
- address: 91.239.100.100
tls: censurfridns-anycast
- address: 89.233.43.71
tls: censurfridns-unicast
forward: first
dnssec_validation: auto
- name: named.conf.local
tls:
- name: censurfridns-anycast
remote_hostname: anycast.uncensoreddns.org
- name: censurfridns-unicast
remote_hostname: unicast.uncensoreddns.org
zones:
- name: example.internal
type: forward
forward: only
forwarders:
- 10.0.0.53
- 10.0.0.54

View File

@@ -2,13 +2,6 @@
driver: driver:
name: podman name: podman
platforms: platforms:
- name: debian-bookworm
image: docker.io/jrei/systemd-debian:12
command: /lib/systemd/systemd
privileged: true
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw
cgroupns_mode: host
- name: debian-trixie - name: debian-trixie
image: docker.io/jrei/systemd-debian:13 image: docker.io/jrei/systemd-debian:13
command: /lib/systemd/systemd command: /lib/systemd/systemd

View File

@@ -4,3 +4,7 @@
- name: Update apt - name: Update apt
ansible.builtin.apt: ansible.builtin.apt:
update_cache: true update_cache: true
- name: Install bind9-dnsutils package
ansible.builtin.apt:
name: bind9-dnsutils
state: present

View File

@@ -0,0 +1,76 @@
---
- name: Verify
hosts: all
gather_facts: true
tasks:
- name: Check that BIND9 is installed
ansible.builtin.package:
name: bind9
state: present
check_mode: true
register: __bind9_package_check
failed_when: __bind9_package_check is changed
- name: Check that BIND9 service is running
ansible.builtin.service:
name: named
state: started
enabled: true
check_mode: true
register: __bind9_service_check
failed_when: __bind9_service_check is changed
- name: Check that named.conf.options exists
ansible.builtin.stat:
path: /etc/bind/named.conf.options
register: __options_file
failed_when: not __options_file.stat.exists
- name: Check that named.conf.local exists
ansible.builtin.stat:
path: /etc/bind/named.conf.local
register: __local_file
failed_when: not __local_file.stat.exists
- name: Read named.conf.options content
ansible.builtin.slurp:
path: /etc/bind/named.conf.options
register: __options_content
- name: Verify forwarders are configured in options
ansible.builtin.assert:
that:
- "'forwarders' in __options_decoded"
- "'8.8.8.8' in __options_decoded"
- "'forward first' in __options_decoded"
fail_msg: Forwarders not properly configured in named.conf.options
vars:
__options_decoded: "{{ __options_content.content | b64decode }}"
- name: Read named.conf.local content
ansible.builtin.slurp:
path: /etc/bind/named.conf.local
register: __local_content
- name: Verify forward zone is configured
ansible.builtin.assert:
that:
- "'zone \"example.internal\"' in __local_decoded"
- "'type forward' in __local_decoded"
- "'forward only' in __local_decoded"
fail_msg: Forward zone not properly configured in named.conf.local
vars:
__local_decoded: "{{ __local_content.content | b64decode }}"
- name: Test DNS resolution using localhost
ansible.builtin.command:
cmd: dig @localhost google.com +short
register: __dns_query
changed_when: false
failed_when: __dns_query.rc != 0
- name: Verify DNS query returned results
ansible.builtin.assert:
that:
- __dns_query.stdout_lines | length > 0
fail_msg: DNS forwarding is not working

View File

@@ -110,4 +110,36 @@
{% else %} {% else %}
{{ name }} "{{ value }}"; {{ name }} "{{ value }}";
{% endif %} {% endif %}
{% endmacro %}
{% macro list_address_port_tls(dict, indent=bind9_config_indent) %}
{# This macro is for use for statements with grammar like #}
{# address port 00 tls str; address port 00 tls str; #}
{# it is usually called by a parent macro #}
{% filter indent(indent, true) %}
{% for item in dict %}
{% if item is not mapping %}
{{ item }};
{% else %}
{{ item.address }}
{{- (' port ' + item.port | string) if item.port is defined and item.port -}}
{{- (' tls ' + item.tls | string) if item.tls is defined and item.tls -}};
{% endif %}
{% endfor %}
{% endfilter %}
{% endmacro %}
{% macro parent_address_port_tls(name, dict) %}
{# This macro is for use for statements with grammar like #}
{# statement port 00 tls str { address port 00 tls str; address port 00 tls str; } #}
{# the list inside the statement is handled by list_address_port_tls #}
{% if dict is not mapping and dict is iterable %}
{{ name }} {
{{ list_address_port_tls(dict) }}};
{% else %}
{{ name }}
{{- (' port ' + dict.port | string) if dict.port is defined and dict.port -}}
{{- (' tls ' + dict.tls | string) if dict.tls is defined and dict.tls }} {
{{ list_address_port_tls(dict.addresses) }}};
{% endif %}
{% endmacro %} {% endmacro %}

View File

@@ -101,7 +101,7 @@ listen-on
{{ functions.simple_item_list(item.options.listen_on.addresses) }}}; {{ functions.simple_item_list(item.options.listen_on.addresses) }}};
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{{ functions.parent_address_port_dscp("forwarders", item.options.forwarders) if item.options.forwarders is defined and item.options.forwarders -}} {{ functions.parent_address_port_tls("forwarders", item.options.forwarders) if item.options.forwarders is defined and item.options.forwarders -}}
{% if item.options.dual_stack_servers is defined and item.options.dual_stack_servers %} {% if item.options.dual_stack_servers is defined and item.options.dual_stack_servers %}
dual-stack-servers dual-stack-servers
{{ (' port ' + item.options.dual_stack_servers.port | string) if item.options.dual_stack_servers.port is defined and item.options.dual_stack_servers }} { {{ (' port ' + item.options.dual_stack_servers.port | string) if item.options.dual_stack_servers.port is defined and item.options.dual_stack_servers }} {

View File

@@ -47,7 +47,7 @@ server-names {
server-addresses { server-addresses {
{{ functions.simple_item_list(zone.server_addresses) }}}; {{ functions.simple_item_list(zone.server_addresses) }}};
{% endif %} {% endif %}
{{ functions.parent_address_port_dscp('forwarders', zone.forwarders) if zone.forwarders is defined and zone.forwarders -}} {{ functions.parent_address_port_tls('forwarders', zone.forwarders) if zone.forwarders is defined and zone.forwarders -}}
{% if zone.allow_transfer is defined and zone.allow_transfer is not string %} {% if zone.allow_transfer is defined and zone.allow_transfer is not string %}
allow-transfer allow-transfer
{{- (' port ' + zone.allow_transfer.port | string) if zone.allow_transfer.port is defined and zone.allow_transfer.port -}} {{- (' port ' + zone.allow_transfer.port | string) if zone.allow_transfer.port is defined and zone.allow_transfer.port -}}