48 Commits

Author SHA1 Message Date
Daniel Akulenok
cb707f2110 Merge branch 'main' into test/verify-ci-fix
Some checks failed
Test / Lint (pull_request) Successful in 16s
Test / Test (pull_request) Failing after 2m12s
2026-02-09 12:41:02 +01:00
Daniel Akulenok
79ac474a85 Merge branch 'main' of ssh://git.valid.dk:2222/daniel/ansible-bind9-role
All checks were successful
Test / Lint (push) Successful in 15s
Test / Test (push) Has been skipped
2026-02-09 12:34:04 +01:00
abd150f581 Merge pull request 'Fix default Molecule scenario and add testing skill' (#18) from fix/molecule-default-test into main
All checks were successful
Test / Lint (push) Successful in 16s
Test / Test (push) Has been skipped
Reviewed-on: #18
2026-02-09 11:33:11 +00:00
Daniel Akulenok
cb20db00af Merge branch 'main' of ssh://git.valid.dk:2222/daniel/ansible-bind9-role
All checks were successful
Test / Lint (push) Successful in 17s
Test / Test (push) Has been skipped
2026-02-09 12:17:45 +01:00
Daniel Akulenok
07f84b7c96 Fix Molecule default scenario tests
Some checks failed
Test / Lint (pull_request) Successful in 16s
Test / Test (pull_request) Failing after 2m12s
2026-02-08 20:43:56 +01:00
Daniel Akulenok
b0d2a914f8 test: Trigger CI pipeline to verify molecule-podman fix
Some checks failed
Test / Lint (pull_request) Successful in 15s
Test / Test (pull_request) Failing after 2m11s
2026-02-08 00:30:39 +01:00
Daniel Akulenok
a4f06d3daf fix: Install molecule-podman driver for CI/CD tests
All checks were successful
Test / Lint (push) Successful in 16s
Test / Test (push) Has been skipped
The test stage was failing because molecule couldn't find the podman
driver. The issue was that 'molecule[podman]' extra doesn't exist in
molecule 25.12.0. Install 'molecule-podman' package instead which
provides the required podman driver for molecule.
2026-02-08 00:29:47 +01:00
Daniel Akulenok
282e7601b4 fix: Add pipefail option to shell command in verify.yml
All checks were successful
Test / Lint (push) Successful in 15s
Test / Test (push) Has been skipped
Resolves ansible-lint risky-shell-pipe violation by adding
'set -o pipefail' to shell task that uses pipes.
2026-02-08 00:26:46 +01:00
f15d33b619 Merge pull request 'feat: Add BIND9 9.20 support with molecule scenario and documentation' (#14) from feature/bind9-20-support into main
Some checks failed
Test / Lint (push) Failing after 15s
Test / Test (push) Has been skipped
Reviewed-on: #14
2026-02-07 23:21:35 +00:00
Daniel Akulenok
a298665e93 fix: Improve BIND9 9.20 molecule scenario testing
Some checks failed
Test / Lint (push) Failing after 15s
Test / Lint (pull_request) Failing after 15s
Test / Test (push) Has been skipped
Test / Test (pull_request) Has been skipped
- Add dnsutils and bind9-doc installation in prepare.yml
  Ensures dig command and documentation are available for testing

- Enhance verify.yml with improved validation:
  - Add named-checkconf syntax validation
  - Improve error detection logic in BIND logs
  - Add explicit error check assertions
  - Increase log tail output from 20 to 30 lines for better diagnostics

These fixes address PR #14 review issues #3, #4, and #5:
- Issue #3: Molecule converge.yml configuration (valid, no changes needed)
- Issue #4: prepare.yml now installs required testing tools
- Issue #5: verify.yml now includes better validation and error checking

Related to: PR #14
2026-02-08 00:20:51 +01:00
Daniel Akulenok
528caeddeb feat: Add BIND9 9.20 molecule scenario and support documentation
Some checks failed
Test / Lint (push) Successful in 15s
Test / Lint (pull_request) Successful in 15s
Test / Test (push) Has been skipped
Test / Test (pull_request) Failing after 34s
- Added molecule/bind9-20 scenario for testing BIND9 9.20+ compatibility
  - molecule.yml: Ubuntu 24.04 platform configuration
  - converge.yml: Complete 9.20 configuration with TLS, DNSTAP, and modern features
  - verify.yml: Comprehensive test cases for 9.20 features
  - collections.yml: Required Ansible collections
  - prepare.yml: Pre-test environment setup
  - README.md: Scenario documentation with breaking changes reference

- Added docs/BIND9_9.20_SUPPORT.md implementation guide
  - Architecture overview for multi-version support
  - Runtime version detection strategy
  - Configuration changes and examples
  - Migration path for upgrading users
  - Feature highlights for BIND9 9.20

- Updated meta/argument_specs.yml
  - Added multi-version support documentation
  - Documented bind9_version variable (read-only, auto-detected)
  - Clarified supported BIND9 versions (9.18.x LTS and 9.20+)

These changes establish the feature/bind9-20-support branch as the development
path for BIND9 9.20+ support, separate from the main branch's 9.18.x focus.

Closes #9: Create feature/bind9-20-support branch with 9.20 templates
2026-02-07 23:58:31 +01:00
Daniel Akulenok
0eff38f202 docs: Add detailed project workflow steps to AGENTS.md
All checks were successful
Test / Lint (push) Successful in 13s
Test / Test (push) Has been skipped
2026-02-07 23:54:25 +01:00
Daniel Akulenok
14a8ff61cf docs: Make AGENTS.md instructions concise and precise
All checks were successful
Test / Lint (push) Successful in 14s
Test / Test (push) Has been skipped
2026-02-07 23:48:14 +01:00
Daniel Akulenok
1c635e5c55 docs: Add comprehensive BIND9 9.18 to 9.20 migration guide
All checks were successful
Test / Lint (push) Successful in 14s
Test / Test (push) Has been skipped
- Create step-by-step migration guide with pre-planning checklist
- Document all 44 breaking changes with explanations
- Provide before/after configuration examples
- Include Ansible role-specific changes and branch selection
- Add DNSSEC policy migration guidance
- Include testing recommendations and validation checklist
- Provide rollback procedures for safe migration
- Link to technical version differences documentation

Closes #6
2026-02-07 23:46:18 +01:00
Daniel Akulenok
db379be31f docs: Add BIND9 version comparison and migration guidance
- Generate BIND_VERSION_DIFFERENCES.md with detailed grammar comparison
- Document 44 breaking changes between BIND9 9.18.44 and 9.20.18
- Document 35 new options and 22 modified options in BIND9 9.20
- Document 3 newly deprecated options
- Add version compatibility section to CONFIGURATION_GRAMMAR.md
- Update CHANGELOG.md with version differences details
- Include migration guide for upgrading from 9.18 to 9.20

Closes #11
2026-02-07 23:43:51 +01:00
Daniel Akulenok
9df24a4a30 docs: Add repository actions guidelines for Gitea interaction
All checks were successful
Test / Lint (push) Successful in 14s
Test / Test (push) Has been skipped
2026-02-07 23:40:16 +01:00
Daniel Akulenok
9622514d84 Merge branch 'main' of ssh://git.valid.dk:2222/daniel/ansible-bind9-role
All checks were successful
Test / Lint (push) Successful in 13s
Test / Test (push) Has been skipped
2026-02-07 23:36:56 +01:00
1ee8ac1e0b Merge pull request 'docs: Add BIND9 grammar files for v9.18.44 and v9.20.18' (#13) from 9.18 into main
All checks were successful
Test / Lint (push) Successful in 13s
Test / Test (push) Has been skipped
Reviewed-on: #13
2026-02-07 22:33:14 +00:00
Daniel Akulenok
4151c9a8c3 docs: Add BIND9 grammar files for v9.18.44 and v9.20.18
Some checks failed
Test / Lint (pull_request) Successful in 12s
Test / Test (pull_request) Failing after 22s
- Fetch official BIND9 configuration grammar files from Gitea mirror
- v9.18.44: Complete grammar including delegation-only.zoneopt
- v9.20.18: Grammar files with v9.20 specific syntax updates
- Files organized in upstream/vX.Y.Z/grammar/ directory structure
- Enables configuration validation and version comparison tooling
- Supports documentation generation and compatibility checking
2026-02-07 23:31:04 +01:00
Daniel Akulenok
6191eaa53a docs: Add branch version marker for 9.18 LTS support
- Identify 9.18 branch as BIND9 9.18.x LTS support line
- Document supported platforms and backporting policies
- Link to version support policy and documentation
2026-02-07 22:53:18 +01:00
Daniel Akulenok
5875c7c1d0 docs: Update README with version compatibility matrix
- Add version support table to README
- Link to VERSION_SUPPORT.md for detailed policies
- Add minimum requirements documentation
- Update license to GPL-3.0-or-later
- Add links to key documentation and contributing info
2026-02-07 22:52:53 +01:00
Daniel Akulenok
4c6a3061bd feat: Add grammar fetch and comparison tooling
- Add fetch_bind_grammar.py for MCP-based grammar file retrieval
- Add compare_bind_versions.py for version differences analysis
- Add process_mcp_result.py for handling base64-encoded MCP output
- Create upstream directory structure with fetching instructions
- Document grammar file locations and structure
2026-02-07 22:52:53 +01:00
Daniel Akulenok
ef45f4ef0b docs: Add version support policy and changelog
- Establish formal version maintenance strategy
- Define BIND9 9.18 (LTS) and 9.20+ support tiers
- Document branching strategy (main for 9.18, 9.20 for next major)
- Define backporting policies for security, bugs, features
- Create release management and CI/CD framework
- Add OS platform compatibility matrix
2026-02-07 22:52:53 +01:00
Daniel Akulenok
3221070075 docs: Update README with version compatibility matrix
- Add version support table to README
- Link to VERSION_SUPPORT.md for detailed policies
- Add minimum requirements documentation
- Update license to GPL-3.0-or-later
- Add links to key documentation and contributing info
2026-02-07 22:52:41 +01:00
Daniel Akulenok
dc4113088e feat: Add grammar fetch and comparison tooling
- Add fetch_bind_grammar.py for MCP-based grammar file retrieval
- Add compare_bind_versions.py for version differences analysis
- Add process_mcp_result.py for handling base64-encoded MCP output
- Create upstream directory structure with fetching instructions
- Document grammar file locations and structure
2026-02-07 22:52:35 +01:00
Daniel Akulenok
149692bcc4 docs: Add version support policy and changelog
- Establish formal version maintenance strategy
- Define BIND9 9.18 (LTS) and 9.20+ support tiers
- Document branching strategy (main for 9.18, 9.20 for next major)
- Define backporting policies for security, bugs, features
- Create release management and CI/CD framework
- Add OS platform compatibility matrix
2026-02-07 22:52:20 +01:00
Daniel Akulenok
0271be7752 Merge branch 'main' of ssh://git.valid.dk:2222/daniel/ansible-bind9-role into HEAD
All checks were successful
Test / Lint (push) Successful in 16s
Test / Test (push) Has been skipped
2026-02-06 14:32:10 +01:00
Daniel Akulenok
907735c294 fix: improve readability of bind9 configuration and update variable registration 2026-02-06 13:46:09 +01:00
Daniel Akulenok
cdcc4cbbda fix: standardize YAML formatting and improve readability in bind9 configuration files 2026-02-06 13:38:56 +01:00
Daniel Akulenok
30918dc9f7 Add zone option JSON files for BIND9 grammar
All checks were successful
Test / Lint (push) Successful in 17s
Test / Test (push) Has been skipped
- Created primary.zoneopt.json to define grammar for primary zones with various options including allow-query, allow-transfer, and DNSSEC settings.
- Added redirect.zoneopt.json for redirect zones, specifying options like allow-query and primaries.
- Introduced secondary.zoneopt.json for secondary zones, detailing options such as allow-notify, forwarders, and notify configurations.
- Implemented static-stub.zoneopt.json for static stub zones, including server-addresses and server-names options.
- Added stub.zoneopt.json for stub zones, defining options like check-names and forwarders.
- Created zoneopt.json as a general template for zone options, incorporating common fields across different zone types.
2026-01-31 22:05:58 +01:00
Daniel Akulenok
7388e4eaaf Merge branch 'main' of ssh://git.valid.dk:2222/daniel/ansible-bind9-role 2026-01-31 21:29:19 +01:00
Daniel Akulenok
f6eee76e05 fix: ensure no change detection for bind9 configuration files
All checks were successful
Test / Lint (push) Successful in 12s
Test / Test (push) Has been skipped
2026-01-28 23:37:37 +01:00
0fede04e19 Merge pull request 'feature/forwarders-port-tls-support' (#3) from feature/forwarders-port-tls-support into main
All checks were successful
Test / Lint (push) Successful in 13s
Test / Test (push) Has been skipped
Reviewed-on: #3
2026-01-28 22:29:11 +00:00
Daniel Akulenok
5f4bb3ccda feat: add podman installation step in CI workflow
Some checks failed
Test / Lint (pull_request) Successful in 12s
Test / Test (push) Has been skipped
Test / Test (pull_request) Failing after 21s
Test / Lint (push) Successful in 13s
2026-01-28 23:27:46 +01:00
Daniel Akulenok
4cb9cb3e3f fix: add noqa comments for linting in workflow and role inclusion
Some checks failed
Test / Lint (push) Successful in 13s
Test / Lint (pull_request) Successful in 13s
Test / Test (push) Has been skipped
Test / Test (pull_request) Failing after 37s
2026-01-28 23:25:35 +01:00
Daniel Akulenok
45d9861960 refactor: remove unnecessary tags from backup removal task
Some checks failed
Test / Lint (push) Failing after 12s
Test / Lint (pull_request) Failing after 12s
Test / Test (push) Has been skipped
Test / Test (pull_request) Has been skipped
2026-01-28 23:22:05 +01:00
Daniel Akulenok
28f8ca5c12 fix: resolve ansible-lint errors
Some checks failed
Test / Lint (push) Failing after 7s
Test / Lint (pull_request) Failing after 6s
Test / Test (push) Has been skipped
Test / Test (pull_request) Has been skipped
- Quote octal file mode values (0640, 0750 -> '0640', '0750')
- Add 'Prepare' name to prepare.yml play
- Fix truthy value in .gitea/workflows/test.yaml (on -> 'on')
- Use role name 'bind9' instead of path in converge.yml
- Move tags to top-level for Deploy and Validate Configuration block
- Remove unnecessary comments to clean up code
- Ensure all YAML and Ansible files pass ansible-lint production profile
2026-01-28 23:20:56 +01:00
Daniel Akulenok
17a9918685 fix: resolve yamllint errors
Some checks failed
Test / Lint (push) Failing after 16s
Test / Lint (pull_request) Failing after 12s
Test / Test (push) Has been skipped
Test / Test (pull_request) Has been skipped
- Fix line length in meta/argument_specs.yml (wrap long description)
- Remove extra blank lines in molecule/default/collections.yml
- Fix line lengths in tasks/main.yml (wrap long messages)
- Remove trailing spaces from tasks/main.yml
- Ensure all YAML files pass yamllint with relaxed profile
2026-01-28 23:15:23 +01:00
Daniel Akulenok
ca70afbd51 ci: add simplified Gitea Actions workflow for testing
Some checks failed
Test / Lint (pull_request) Failing after 42s
Test / Test (pull_request) Has been skipped
- Add yamllint for YAML style validation (relaxed profile)
- Add ansible-lint for Ansible best practices (production profile)
- Add Molecule test job that runs only on pull requests
- Lint job runs on all push events to main and feature branches
- Test job depends on lint job passing
- Clean, maintainable pipeline configuration
2026-01-28 23:11:04 +01:00
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
Daniel Akulenok
fa35922646 AGENTS 2026-01-28 22:03:18 +01:00
Daniel Akulenok
3d7a403409 fix: Update issue tracker URL in metadata 2026-01-27 23:42:07 +01:00
Daniel Akulenok
30098d48d8 fix: Update issue tracker URL in metadata 2026-01-27 23:40:56 +01:00
73 changed files with 10328 additions and 55 deletions

43
.bind9version Normal file
View File

@@ -0,0 +1,43 @@
# BIND9 9.18 LTS Support Branch
Branch: 9.18
Purpose: Long-term support for BIND9 9.18.x (ISC LTS release)
Status: Active
Support Level: Full
## Version Information
- **BIND9 Version**: 9.18.x (LTS)
- **Supported Until**: Aligned with ISC BIND9 9.18 LTS support timeline
- **Branch Base**: BIND9 9.18.44 (as of February 2026)
## Supported Platforms
- Debian 11 (Bullseye)
- Debian 12 (Bookworm)
- Debian 13 (Trixie)
- Ubuntu 20.04 LTS
- Ubuntu 22.04 LTS
- Ubuntu 24.04 LTS
## Policies
### Backporting
- ✅ Security fixes: Always backported
- ✅ Bug fixes: Backported if compatible
- ❌ New features: Case-by-case (no breaking changes)
- ❌ Breaking changes: Never
### Release Numbering
Uses MAJOR.MINOR.PATCH (e.g., v1.2.3)
## Key Documentation
- [Version Support Policy](docs/VERSION_SUPPORT.md)
- [Configuration Grammar](CONFIGURATION_GRAMMAR.md)
- [Changelog](CHANGELOG.md)
- [README](README.md)
## Next Major Version
For BIND9 9.20+ support, see the `main` branch which will eventually have version-specific releases.

View File

@@ -0,0 +1,63 @@
---
name: Test
on: # noqa: yaml[truthy]
push:
branches:
- main
- feature/**
pull_request:
branches:
- main
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install tools
run: |
pip install --no-cache-dir yamllint ansible-lint
- name: Run yamllint
run: yamllint -d relaxed .
- name: Run ansible-lint
run: ansible-lint --strict --profile=production
test:
name: Test
runs-on: ubuntu-latest
needs: lint
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install podman
run: |
sudo apt-get update
sudo apt-get install -y podman
- name: Install dependencies
run: |
pip install --no-cache-dir \
ansible \
molecule \
molecule-podman \
pyyaml \
jinja2
- name: Run Molecule tests
run: molecule test

View File

@@ -0,0 +1,31 @@
---
name: molecule-role-testing
description: Run Molecule scenarios to test the bind9 role using the repository's Molecule configuration.
---
Use this skill when asked to test or validate the role with Molecule.
## Scope
- Repository root: /home/alive/Code/ansible-bind9-role
- Scenarios: molecule/default and molecule/bind9-20
- Driver: podman
## Prerequisites
1. Ensure Podman is available and the current user can run it.
2. Ensure Molecule and Ansible are installed in the active Python environment.
## Default scenario (BIND 9.18 LTS)
1. From the repository root, run:
- molecule test
2. If a faster check is requested, run:
- molecule converge
## BIND 9.20+ scenario
1. From the repository root, run:
- molecule test -s bind9-20
2. If a faster check is requested, run:
- molecule converge -s bind9-20
## Notes
- The scenarios use systemd-enabled containers and require privileged Podman.
- If a scenario fails, capture the error summary and relevant logs before making changes.

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
Testing CI fix

44
AGENTS.md Normal file
View File

@@ -0,0 +1,44 @@
<!--# cspell: ignore SSOT CMDB -->
# AGENTS.md
Ensure that all practices and instructions described by
https://raw.githubusercontent.com/ansible/ansible-creator/refs/heads/main/docs/agents.md
are followed.
## Repository Actions
**Use gitea-mcp tools for all repository interactions.** Do not use `curl`, `git`, or direct API calls.
### When to Use gitea-mcp
- Fetching issues, PRs, branches, tags, releases
- Reading files, directories, or commits from repo
- Creating issues, PRs, comments, tags, or releases
- Editing issues or PRs
### Wrong vs Right
`curl http://git.valid.dk/api/v1/repos/daniel/ansible-bind9-role/issues/6`
`mcp_gitea-mcp_list_repo_issues(owner, repo, page, pageSize)`
### Local Workspace
Terminal commands are fine for:
- Compiling, testing, building
- Git operations on local files (commit, push)
- Using `read_file`, `grep_search`, `semantic_search`
## General project workflow
1. Check for open tickets
2. Choose next logical ticket to work on
3. Create branch for ticket
4. Create plan for ticket
5. Execute plan
6. Create appropriate commits to repository
7. Submit PR to repository
8. Review the PR critically
9. Check if further work is needed to resolve the issues found
10. Loop 8-9 until complete
11. Ask me to review the PR and merge it
12. Close the ticket

120
CHANGELOG.md Normal file
View File

@@ -0,0 +1,120 @@
# Changelog
All notable changes to the ansible-bind9-role will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- Version support policy documentation in `docs/VERSION_SUPPORT.md`
- Branching strategy for supporting multiple BIND9 versions
- Grammar comparison tooling (`scripts/compare_bind_versions.py`)
- Grammar fetcher for upstream BIND9 sources (`scripts/fetch_bind_grammar.py`)
- Automated version difference tracking
- Operating system support matrix
- BIND9 Version Differences documentation (`docs/BIND_VERSION_DIFFERENCES.md`) covering:
- 44 breaking changes between BIND9 9.18.44 and 9.20.18
- 35 new options in BIND9 9.20
- 22 modified options requiring configuration updates
- 3 newly deprecated options
### Changed
- Established formal release management process
- Defined backporting policy for security, bugs, and features
- Clarified version compatibility in CONFIGURATION_GRAMMAR.md
### Planned
- BIND9 9.20+ support in separate `9.20` branch
- Multi-platform molecule test matrix
- Automated BIND9 version detection in tasks
- Version-specific template conditional logic
- Enhanced CI/CD pipeline with version matrix testing
## [1.0.0] - TBD
### Initial Release
- Full support for BIND9 9.18.x (LTS)
- Configuration grammar based on BIND9 9.18.44
- Comprehensive template system for all BIND9 statement types:
- `acl`
- `controls`
- `dlz`
- `dnssec-policy`
- `dyndb`
- `http`
- `key`
- `logging`
- `options`
- `parental-agents`
- `primaries` (masters)
- `server`
- `statistics-channels`
- `tls`
- `trust-anchors`
- `view`
- `zone` (all types: primary, secondary, forward, hint, stub, static-stub, mirror, redirect, in-view, delegation-only)
- Support for Debian 11, 12, 13
- Support for Ubuntu 20.04, 22.04, 24.04
- Molecule testing framework
- Configuration validation with `named-checkconf`
- Automatic configuration backup and rollback on errors
- Detailed configuration grammar documentation
- GPL-3.0-or-later license
---
## Version History (Pre-Changelog)
Prior to this changelog, the role was developed without formal version tracking.
This changelog starts with the establishment of the version support policy.
---
## Versioning Schema
- **MAJOR**: Incompatible changes to role variables or behavior
- **MINOR**: New features in a backwards compatible manner
- **PATCH**: Backwards compatible bug fixes
### Branch-Specific Versioning
- `main` branch: `vX.Y.Z` (BIND9 9.18 LTS)
- `9.20` branch: `v9.20.X[-suffix]` (BIND9 9.20+)
- Suffixes: `-alpha`, `-beta`, `-rc` for pre-releases
## Release Types
### Security Releases
Critical security fixes are released as patch versions and backported to all supported branches.
### Feature Releases
New features are added in minor version increments. Breaking changes require major version increments.
### Bug Fix Releases
Bug fixes are released as patch versions when they accumulate or for critical issues.
## Upgrade Notes
### From Pre-Versioned to v1.0.0
The first official release establishes baseline compatibility. Users of pre-release versions should:
1. Review all role variables for any changes
2. Test in non-production environment
3. Review generated configuration with `named-checkconf`
4. Check `docs/VERSION_SUPPORT.md` for supported platforms
### Future Upgrades
Check individual version sections above for specific upgrade notes and breaking changes.
## Contributing
See `docs/VERSION_SUPPORT.md` for contribution guidelines and release processes.
## Links
- [Version Support Policy](docs/VERSION_SUPPORT.md)
- [Configuration Grammar](CONFIGURATION_GRAMMAR.md)
- [Issue Tracker](https://git.valid.dk/daniel/ansible-bind9-role/issues)
- [Repository](https://git.valid.dk/daniel/ansible-bind9-role)

1381
CONFIGURATION_GRAMMAR.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,19 @@ bind9
A feature-complete ansible role for installing and configuring bind9. The purpose of this role is to fully template out the entire official bind9 configuration file format. A feature-complete ansible role for installing and configuring bind9. The purpose of this role is to fully template out the entire official bind9 configuration file format.
## Version Compatibility
| BIND9 Version | Role Branch | Status | Supported Platforms |
|---------------|-------------|--------|---------------------|
| 9.18.x (LTS) | `main` | ✅ Supported | Debian 11-13, Ubuntu 20.04-24.04 |
| 9.20.x+ | `9.20` | 🚧 Planned | Debian 12-13, Ubuntu 22.04-24.04 |
For detailed version support policy, branching strategy, and migration guidance, see [docs/VERSION_SUPPORT.md](docs/VERSION_SUPPORT.md).
**Minimum Requirements:**
- Ansible: 2.13+
- Python: 3.8+
What the role does: What the role does:
- Fully configures named.conf - Fully configures named.conf
- Checks that the config is valid - Checks that the config is valid
@@ -126,38 +139,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
``` ```
@@ -190,10 +208,30 @@ Simple sample config of a recursive BIND server that allows your localnetwork to
allow-recursion: allow-recursion:
- mylan - mylan
## Documentation
- **[Configuration Grammar Reference](CONFIGURATION_GRAMMAR.md)**: Comprehensive guide to all BIND9 configuration options
- **[Version Support Policy](docs/VERSION_SUPPORT.md)**: Supported versions, branching strategy, and release management
- **[Changelog](CHANGELOG.md)**: Version history and upgrade notes
## Contributing
Contributions are welcome! Please see [docs/VERSION_SUPPORT.md](docs/VERSION_SUPPORT.md) for:
- Branching strategy
- Testing requirements
- Backporting policies
- Release procedures
## Links
- **Repository**: https://git.valid.dk/daniel/ansible-bind9-role
- **Issues**: https://git.valid.dk/daniel/ansible-bind9-role/issues
- **BIND9 Documentation**: https://bind9.readthedocs.io/
License License
------- -------
BSD GPL-3.0-or-later
Author Information Author Information
------------------ ------------------

View File

@@ -0,0 +1,19 @@
{
"zone": {
"_id": "<string> [ <class> ]",
"_mapbody": {
"type": {
"_grammar": "forward"
},
"forward": {
"_grammar": "( first | only )"
},
"forwarders": {
"_grammar": "[ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... }"
},
"template": {
"_grammar": "<string>"
}
}
}
}

View File

@@ -0,0 +1,19 @@
{
"zone": {
"_id": "<string> [ <class> ]",
"_mapbody": {
"type": {
"_grammar": "hint"
},
"check-names": {
"_grammar": "( fail | warn | ignore )"
},
"file": {
"_grammar": "<quoted_string>"
},
"template": {
"_grammar": "<string>"
}
}
}
}

View File

@@ -0,0 +1,10 @@
{
"zone": {
"_id": "<string> [ <class> ]",
"_mapbody": {
"in-view": {
"_grammar": "<string>"
}
}
}
}

View File

@@ -0,0 +1,171 @@
{
"zone": {
"_id": "<string> [ <class> ]",
"_mapbody": {
"type": {
"_grammar": "mirror"
},
"allow-notify": {
"_grammar": "{ <address_match_element>; ... }"
},
"allow-query": {
"_grammar": "{ <address_match_element>; ... }"
},
"allow-query-on": {
"_grammar": "{ <address_match_element>; ... }"
},
"allow-transfer": {
"_grammar": "[ port <integer> ] [ transport <string> ] { <address_match_element>; ... }"
},
"allow-update-forwarding": {
"_grammar": "{ <address_match_element>; ... }"
},
"also-notify": {
"_grammar": "[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... }"
},
"check-names": {
"_grammar": "( fail | warn | ignore )"
},
"database": {
"_grammar": "<string>"
},
"file": {
"_grammar": "<quoted_string>"
},
"ixfr-from-differences": {
"_grammar": "<boolean>"
},
"journal": {
"_grammar": "<quoted_string>"
},
"masterfile-format": {
"_grammar": "( raw | text )"
},
"masterfile-style": {
"_grammar": "( full | relative )"
},
"max-ixfr-ratio": {
"_grammar": "( unlimited | <percentage> )"
},
"max-journal-size": {
"_grammar": "( default | unlimited | <sizeval> )"
},
"max-records": {
"_grammar": "<integer>"
},
"max-records-per-type": {
"_grammar": "<integer>"
},
"max-refresh-time": {
"_grammar": "<integer>"
},
"max-retry-time": {
"_grammar": "<integer>"
},
"max-transfer-idle-in": {
"_grammar": "<integer>"
},
"max-transfer-idle-out": {
"_grammar": "<integer>"
},
"max-transfer-time-in": {
"_grammar": "<integer>"
},
"max-transfer-time-out": {
"_grammar": "<integer>"
},
"max-types-per-name": {
"_grammar": "<integer>"
},
"min-refresh-time": {
"_grammar": "<integer>"
},
"min-retry-time": {
"_grammar": "<integer>"
},
"min-transfer-rate-in": {
"_grammar": "<integer> <integer>"
},
"multi-master": {
"_grammar": "<boolean>"
},
"notify": {
"_grammar": "( explicit | master-only | primary-only | <boolean> )"
},
"notify-cfg": {
"_flags": [
"may occur multiple times"
],
"_id": "<string>",
"_mapbody": {
"notify": {
"_grammar": "<boolean>"
},
"notify-defer": {
"_grammar": "<integer>"
},
"notify-delay": {
"_grammar": "<integer>"
},
"notify-source": {
"_grammar": "( <ipv4_address> | * )"
},
"notify-source-v6": {
"_grammar": "( <ipv6_address> | * )"
}
}
},
"notify-defer": {
"_grammar": "<integer>"
},
"notify-delay": {
"_grammar": "<integer>"
},
"notify-source": {
"_grammar": "( <ipv4_address> | * )"
},
"notify-source-v6": {
"_grammar": "( <ipv6_address> | * )"
},
"plugin": {
"_flags": [
"may occur multiple times"
],
"_grammar": "( query ) <string> [ { <unspecified-text> } ]"
},
"primaries": {
"_grammar": "[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... }"
},
"provide-zoneversion": {
"_grammar": "<boolean>"
},
"request-expire": {
"_grammar": "<boolean>"
},
"request-ixfr": {
"_grammar": "<boolean>"
},
"request-ixfr-max-diffs": {
"_grammar": "<integer>"
},
"template": {
"_grammar": "<string>"
},
"transfer-source": {
"_grammar": "( <ipv4_address> | * )"
},
"transfer-source-v6": {
"_grammar": "( <ipv6_address> | * )"
},
"try-tcp-refresh": {
"_grammar": "<boolean>"
},
"zero-no-soa-ttl": {
"_grammar": "<boolean>"
},
"zone-statistics": {
"_grammar": "( full | terse | none | <boolean> )"
}
}
}
}

2315
bind9-grammar/options.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,258 @@
{
"zone": {
"_id": "<string> [ <class> ]",
"_mapbody": {
"type": {
"_grammar": "primary"
},
"allow-query": {
"_grammar": "{ <address_match_element>; ... }"
},
"allow-query-on": {
"_grammar": "{ <address_match_element>; ... }"
},
"allow-transfer": {
"_grammar": "[ port <integer> ] [ transport <string> ] { <address_match_element>; ... }"
},
"allow-update": {
"_grammar": "{ <address_match_element>; ... }"
},
"also-notify": {
"_grammar": "[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... }"
},
"check-dup-records": {
"_grammar": "( fail | warn | ignore )"
},
"check-integrity": {
"_grammar": "<boolean>"
},
"check-mx": {
"_grammar": "( fail | warn | ignore )"
},
"check-mx-cname": {
"_grammar": "( fail | warn | ignore )"
},
"check-names": {
"_grammar": "( fail | warn | ignore )"
},
"check-sibling": {
"_grammar": "<boolean>"
},
"check-spf": {
"_grammar": "( warn | ignore )"
},
"check-srv-cname": {
"_grammar": "( fail | warn | ignore )"
},
"check-svcb": {
"_grammar": "<boolean>"
},
"check-wildcard": {
"_grammar": "<boolean>"
},
"checkds": {
"_grammar": "( explicit | <boolean> )"
},
"database": {
"_grammar": "<string>"
},
"dlz": {
"_grammar": "<string>"
},
"dnskey-sig-validity": {
"_flags": [
"obsolete"
],
"_grammar": "<integer>"
},
"dnssec-dnskey-kskonly": {
"_flags": [
"obsolete"
],
"_grammar": "<boolean>"
},
"dnssec-loadkeys-interval": {
"_grammar": "<integer>"
},
"dnssec-policy": {
"_grammar": "<string>"
},
"dnssec-secure-to-insecure": {
"_flags": [
"obsolete"
],
"_grammar": "<boolean>"
},
"dnssec-update-mode": {
"_flags": [
"obsolete"
],
"_grammar": "( maintain | no-resign )"
},
"file": {
"_grammar": "<quoted_string>"
},
"forward": {
"_grammar": "( first | only )"
},
"forwarders": {
"_grammar": "[ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... }"
},
"initial-file": {
"_grammar": "<quoted_string>"
},
"inline-signing": {
"_grammar": "<boolean>"
},
"ixfr-from-differences": {
"_grammar": "<boolean>"
},
"journal": {
"_grammar": "<quoted_string>"
},
"key-directory": {
"_grammar": "<quoted_string>"
},
"log-report-channel": {
"_grammar": "<boolean>"
},
"masterfile-format": {
"_grammar": "( raw | text )"
},
"masterfile-style": {
"_grammar": "( full | relative )"
},
"max-ixfr-ratio": {
"_grammar": "( unlimited | <percentage> )"
},
"max-journal-size": {
"_grammar": "( default | unlimited | <sizeval> )"
},
"max-records": {
"_grammar": "<integer>"
},
"max-records-per-type": {
"_grammar": "<integer>"
},
"max-transfer-idle-out": {
"_grammar": "<integer>"
},
"max-transfer-time-out": {
"_grammar": "<integer>"
},
"max-types-per-name": {
"_grammar": "<integer>"
},
"max-zone-ttl": {
"_flags": [
"deprecated"
],
"_grammar": "( unlimited | <duration> )"
},
"notify": {
"_grammar": "( explicit | master-only | primary-only | <boolean> )"
},
"notify-cfg": {
"_flags": [
"may occur multiple times"
],
"_id": "<string>",
"_mapbody": {
"notify": {
"_grammar": "<boolean>"
},
"notify-defer": {
"_grammar": "<integer>"
},
"notify-delay": {
"_grammar": "<integer>"
},
"notify-source": {
"_grammar": "( <ipv4_address> | * )"
},
"notify-source-v6": {
"_grammar": "( <ipv6_address> | * )"
}
}
},
"notify-defer": {
"_grammar": "<integer>"
},
"notify-delay": {
"_grammar": "<integer>"
},
"notify-source": {
"_grammar": "( <ipv4_address> | * )"
},
"notify-source-v6": {
"_grammar": "( <ipv6_address> | * )"
},
"notify-to-soa": {
"_grammar": "<boolean>"
},
"nsec3-test-zone": {
"_flags": [
"test only"
],
"_grammar": "<boolean>"
},
"parental-agents": {
"_grammar": "[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... }"
},
"parental-source": {
"_grammar": "( <ipv4_address> | * )"
},
"parental-source-v6": {
"_grammar": "( <ipv6_address> | * )"
},
"plugin": {
"_flags": [
"may occur multiple times"
],
"_grammar": "( query ) <string> [ { <unspecified-text> } ]"
},
"provide-zoneversion": {
"_grammar": "<boolean>"
},
"send-report-channel": {
"_grammar": "<string>"
},
"serial-update-method": {
"_grammar": "( date | increment | unixtime )"
},
"sig-signing-nodes": {
"_grammar": "<integer>"
},
"sig-signing-signatures": {
"_grammar": "<integer>"
},
"sig-signing-type": {
"_grammar": "<integer>"
},
"sig-validity-interval": {
"_flags": [
"obsolete"
],
"_grammar": "<integer> [ <integer> ]"
},
"template": {
"_grammar": "<string>"
},
"update-check-ksk": {
"_flags": [
"obsolete"
],
"_grammar": "<boolean>"
},
"update-policy": {
"_grammar": "( local | { ( deny | grant ) <string> ( 6to4-self | external | krb5-self | krb5-selfsub | krb5-subdomain | krb5-subdomain-self-rhs | ms-self | ms-selfsub | ms-subdomain | ms-subdomain-self-rhs | name | self | selfsub | selfwild | subdomain | tcp-self | wildcard | zonesub ) [ <string> ] <rrtypelist>; ... } )"
},
"zero-no-soa-ttl": {
"_grammar": "<boolean>"
},
"zone-statistics": {
"_grammar": "( full | terse | none | <boolean> )"
}
}
}
}

View File

@@ -0,0 +1,58 @@
{
"zone": {
"_id": "<string> [ <class> ]",
"_mapbody": {
"type": {
"_grammar": "redirect"
},
"allow-query": {
"_grammar": "{ <address_match_element>; ... }"
},
"allow-query-on": {
"_grammar": "{ <address_match_element>; ... }"
},
"dlz": {
"_grammar": "<string>"
},
"file": {
"_grammar": "<quoted_string>"
},
"masterfile-format": {
"_grammar": "( raw | text )"
},
"masterfile-style": {
"_grammar": "( full | relative )"
},
"max-records": {
"_grammar": "<integer>"
},
"max-records-per-type": {
"_grammar": "<integer>"
},
"max-types-per-name": {
"_grammar": "<integer>"
},
"max-zone-ttl": {
"_flags": [
"deprecated"
],
"_grammar": "( unlimited | <duration> )"
},
"plugin": {
"_flags": [
"may occur multiple times"
],
"_grammar": "( query ) <string> [ { <unspecified-text> } ]"
},
"primaries": {
"_grammar": "[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... }"
},
"template": {
"_grammar": "<string>"
},
"zone-statistics": {
"_grammar": "( full | terse | none | <boolean> )"
}
}
}
}

View File

@@ -0,0 +1,258 @@
{
"zone": {
"_id": "<string> [ <class> ]",
"_mapbody": {
"type": {
"_grammar": "secondary"
},
"allow-notify": {
"_grammar": "{ <address_match_element>; ... }"
},
"allow-query": {
"_grammar": "{ <address_match_element>; ... }"
},
"allow-query-on": {
"_grammar": "{ <address_match_element>; ... }"
},
"allow-transfer": {
"_grammar": "[ port <integer> ] [ transport <string> ] { <address_match_element>; ... }"
},
"allow-update-forwarding": {
"_grammar": "{ <address_match_element>; ... }"
},
"also-notify": {
"_grammar": "[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... }"
},
"check-names": {
"_grammar": "( fail | warn | ignore )"
},
"checkds": {
"_grammar": "( explicit | <boolean> )"
},
"database": {
"_grammar": "<string>"
},
"dlz": {
"_grammar": "<string>"
},
"dnskey-sig-validity": {
"_flags": [
"obsolete"
],
"_grammar": "<integer>"
},
"dnssec-dnskey-kskonly": {
"_flags": [
"obsolete"
],
"_grammar": "<boolean>"
},
"dnssec-loadkeys-interval": {
"_grammar": "<integer>"
},
"dnssec-policy": {
"_grammar": "<string>"
},
"dnssec-update-mode": {
"_flags": [
"obsolete"
],
"_grammar": "( maintain | no-resign )"
},
"file": {
"_grammar": "<quoted_string>"
},
"forward": {
"_grammar": "( first | only )"
},
"forwarders": {
"_grammar": "[ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... }"
},
"inline-signing": {
"_grammar": "<boolean>"
},
"ixfr-from-differences": {
"_grammar": "<boolean>"
},
"journal": {
"_grammar": "<quoted_string>"
},
"key-directory": {
"_grammar": "<quoted_string>"
},
"log-report-channel": {
"_grammar": "<boolean>"
},
"masterfile-format": {
"_grammar": "( raw | text )"
},
"masterfile-style": {
"_grammar": "( full | relative )"
},
"max-ixfr-ratio": {
"_grammar": "( unlimited | <percentage> )"
},
"max-journal-size": {
"_grammar": "( default | unlimited | <sizeval> )"
},
"max-records": {
"_grammar": "<integer>"
},
"max-records-per-type": {
"_grammar": "<integer>"
},
"max-refresh-time": {
"_grammar": "<integer>"
},
"max-retry-time": {
"_grammar": "<integer>"
},
"max-transfer-idle-in": {
"_grammar": "<integer>"
},
"max-transfer-idle-out": {
"_grammar": "<integer>"
},
"max-transfer-time-in": {
"_grammar": "<integer>"
},
"max-transfer-time-out": {
"_grammar": "<integer>"
},
"max-types-per-name": {
"_grammar": "<integer>"
},
"min-refresh-time": {
"_grammar": "<integer>"
},
"min-retry-time": {
"_grammar": "<integer>"
},
"min-transfer-rate-in": {
"_grammar": "<integer> <integer>"
},
"multi-master": {
"_grammar": "<boolean>"
},
"notify": {
"_grammar": "( explicit | master-only | primary-only | <boolean> )"
},
"notify-cfg": {
"_flags": [
"may occur multiple times"
],
"_id": "<string>",
"_mapbody": {
"notify": {
"_grammar": "<boolean>"
},
"notify-defer": {
"_grammar": "<integer>"
},
"notify-delay": {
"_grammar": "<integer>"
},
"notify-source": {
"_grammar": "( <ipv4_address> | * )"
},
"notify-source-v6": {
"_grammar": "( <ipv6_address> | * )"
}
}
},
"notify-defer": {
"_grammar": "<integer>"
},
"notify-delay": {
"_grammar": "<integer>"
},
"notify-source": {
"_grammar": "( <ipv4_address> | * )"
},
"notify-source-v6": {
"_grammar": "( <ipv6_address> | * )"
},
"notify-to-soa": {
"_grammar": "<boolean>"
},
"nsec3-test-zone": {
"_flags": [
"test only"
],
"_grammar": "<boolean>"
},
"parental-agents": {
"_grammar": "[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... }"
},
"parental-source": {
"_grammar": "( <ipv4_address> | * )"
},
"parental-source-v6": {
"_grammar": "( <ipv6_address> | * )"
},
"plugin": {
"_flags": [
"may occur multiple times"
],
"_grammar": "( query ) <string> [ { <unspecified-text> } ]"
},
"primaries": {
"_grammar": "[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... }"
},
"provide-zoneversion": {
"_grammar": "<boolean>"
},
"request-expire": {
"_grammar": "<boolean>"
},
"request-ixfr": {
"_grammar": "<boolean>"
},
"request-ixfr-max-diffs": {
"_grammar": "<integer>"
},
"send-report-channel": {
"_grammar": "<string>"
},
"sig-signing-nodes": {
"_grammar": "<integer>"
},
"sig-signing-signatures": {
"_grammar": "<integer>"
},
"sig-signing-type": {
"_grammar": "<integer>"
},
"sig-validity-interval": {
"_flags": [
"obsolete"
],
"_grammar": "<integer> [ <integer> ]"
},
"template": {
"_grammar": "<string>"
},
"transfer-source": {
"_grammar": "( <ipv4_address> | * )"
},
"transfer-source-v6": {
"_grammar": "( <ipv6_address> | * )"
},
"try-tcp-refresh": {
"_grammar": "<boolean>"
},
"update-check-ksk": {
"_flags": [
"obsolete"
],
"_grammar": "<boolean>"
},
"zero-no-soa-ttl": {
"_grammar": "<boolean>"
},
"zone-statistics": {
"_grammar": "( full | terse | none | <boolean> )"
}
}
}
}

View File

@@ -0,0 +1,43 @@
{
"zone": {
"_id": "<string> [ <class> ]",
"_mapbody": {
"type": {
"_grammar": "static-stub"
},
"allow-query": {
"_grammar": "{ <address_match_element>; ... }"
},
"allow-query-on": {
"_grammar": "{ <address_match_element>; ... }"
},
"forward": {
"_grammar": "( first | only )"
},
"forwarders": {
"_grammar": "[ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... }"
},
"max-records": {
"_grammar": "<integer>"
},
"max-records-per-type": {
"_grammar": "<integer>"
},
"max-types-per-name": {
"_grammar": "<integer>"
},
"server-addresses": {
"_grammar": "{ ( <ipv4_address> | <ipv6_address> ); ... }"
},
"server-names": {
"_grammar": "{ <string>; ... }"
},
"template": {
"_grammar": "<string>"
},
"zone-statistics": {
"_grammar": "( full | terse | none | <boolean> )"
}
}
}
}

View File

@@ -0,0 +1,85 @@
{
"zone": {
"_id": "<string> [ <class> ]",
"_mapbody": {
"type": {
"_grammar": "stub"
},
"allow-query": {
"_grammar": "{ <address_match_element>; ... }"
},
"allow-query-on": {
"_grammar": "{ <address_match_element>; ... }"
},
"check-names": {
"_grammar": "( fail | warn | ignore )"
},
"database": {
"_grammar": "<string>"
},
"file": {
"_grammar": "<quoted_string>"
},
"forward": {
"_grammar": "( first | only )"
},
"forwarders": {
"_grammar": "[ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... }"
},
"masterfile-format": {
"_grammar": "( raw | text )"
},
"masterfile-style": {
"_grammar": "( full | relative )"
},
"max-records": {
"_grammar": "<integer>"
},
"max-records-per-type": {
"_grammar": "<integer>"
},
"max-refresh-time": {
"_grammar": "<integer>"
},
"max-retry-time": {
"_grammar": "<integer>"
},
"max-transfer-idle-in": {
"_grammar": "<integer>"
},
"max-transfer-time-in": {
"_grammar": "<integer>"
},
"max-types-per-name": {
"_grammar": "<integer>"
},
"min-refresh-time": {
"_grammar": "<integer>"
},
"min-retry-time": {
"_grammar": "<integer>"
},
"min-transfer-rate-in": {
"_grammar": "<integer> <integer>"
},
"multi-master": {
"_grammar": "<boolean>"
},
"primaries": {
"_grammar": "[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... }"
},
"template": {
"_grammar": "<string>"
},
"transfer-source": {
"_grammar": "( <ipv4_address> | * )"
},
"transfer-source-v6": {
"_grammar": "( <ipv6_address> | * )"
},
"zone-statistics": {
"_grammar": "( full | terse | none | <boolean> )"
}
}
}
}

View File

@@ -0,0 +1,54 @@
# BIND9 Grammar Files - Upstream Source
This directory contains upstream BIND9 grammar files from the official BIND9 mirror for version comparison and validation.
## Files to Fetch
When grammar files are needed, fetch from:
- **Repository**: https://git.valid.dk/Mirrors/bind9
- **9.18 Tag**: v9.18.44
- **9.20 Tag**: v9.20.18
### Required Grammar Files (from doc/misc/)
- options
- forward.zoneopt
- hint.zoneopt
- in-view.zoneopt
- mirror.zoneopt
- primary.zoneopt
- redirect.zoneopt
- secondary.zoneopt
- static-stub.zoneopt
- stub.zoneopt
- delegation-only.zoneopt
- rndc.grammar
- parsegrammar.py
- checkgrammar.py
## Directory Structure
```
upstream/
├── v9.18.44/
│ ├── grammar/ (Grammar files)
│ └── metadata.json (Fetch metadata)
└── v9.20.18/
├── grammar/ (Grammar files)
└── metadata.json (Fetch metadata)
```
## Fetching
Option 1: Using git fetch
```bash
git clone --depth 1 --branch v9.18.44 https://git.valid.dk/Mirrors/bind9.git /tmp/bind9-9.18
cp /tmp/bind9-9.18/doc/misc/* bind9-grammar/upstream/v9.18.44/grammar/
```
Option 2: Using Gitea MCP tools (see scripts/fetch_bind_grammar.py)
## Scripts
- `scripts/fetch_bind_grammar.py` - MCP-based fetcher template
- `scripts/compare_bind_versions.py` - Grammar comparison tool

View File

@@ -0,0 +1,3 @@
zone <string> [ <class> ] {
type delegation-only;
};

View File

@@ -0,0 +1,6 @@
zone <string> [ <class> ] {
type forward;
delegation-only <boolean>; // deprecated
forward ( first | only );
forwarders [ port <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ]; ... };
};

View File

@@ -0,0 +1,6 @@
zone <string> [ <class> ] {
type hint;
check-names ( fail | warn | ignore );
delegation-only <boolean>; // deprecated
file <quoted_string>;
};

View File

@@ -0,0 +1,3 @@
zone <string> [ <class> ] {
in-view <string>;
};

View File

@@ -0,0 +1,45 @@
zone <string> [ <class> ] {
type mirror;
allow-notify { <address_match_element>; ... };
allow-query { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
allow-transfer [ port <integer> ] [ transport <string> ] { <address_match_element>; ... };
allow-update-forwarding { <address_match_element>; ... };
also-notify [ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
alt-transfer-source ( <ipv4_address> | * ) ; // deprecated
alt-transfer-source-v6 ( <ipv6_address> | * ) ; // deprecated
check-names ( fail | warn | ignore );
database <string>;
file <quoted_string>;
ixfr-from-differences <boolean>;
journal <quoted_string>;
masterfile-format ( raw | text );
masterfile-style ( full | relative );
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
max-records-per-type <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
max-types-per-name <integer>;
min-refresh-time <integer>;
min-retry-time <integer>;
multi-master <boolean>;
notify ( explicit | master-only | primary-only | <boolean> );
notify-delay <integer>;
notify-source ( <ipv4_address> | * ) ;
notify-source-v6 ( <ipv6_address> | * ) ;
primaries [ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
request-expire <boolean>;
request-ixfr <boolean>;
transfer-source ( <ipv4_address> | * ) ;
transfer-source-v6 ( <ipv6_address> | * ) ;
try-tcp-refresh <boolean>;
use-alt-transfer-source <boolean>; // deprecated
zero-no-soa-ttl <boolean>;
zone-statistics ( full | terse | none | <boolean> );
};

View File

@@ -0,0 +1,604 @@
acl <string> { <address_match_element>; ... }; // may occur multiple times
controls {
inet ( <ipv4_address> | <ipv6_address> | * ) [ port ( <integer> | * ) ] allow { <address_match_element>; ... } [ keys { <string>; ... } ] [ read-only <boolean> ]; // may occur multiple times
unix <quoted_string> perm <integer> owner <integer> group <integer> [ keys { <string>; ... } ] [ read-only <boolean> ]; // may occur multiple times
}; // may occur multiple times
dlz <string> {
database <string>;
search <boolean>;
}; // may occur multiple times
dnssec-policy <string> {
dnskey-ttl <duration>;
keys { ( csk | ksk | zsk ) [ ( key-directory ) ] lifetime <duration_or_unlimited> algorithm <string> [ <integer> ]; ... };
max-zone-ttl <duration>;
nsec3param [ iterations <integer> ] [ optout <boolean> ] [ salt-length <integer> ];
parent-ds-ttl <duration>;
parent-propagation-delay <duration>;
parent-registration-delay <duration>; // obsolete
publish-safety <duration>;
purge-keys <duration>;
retire-safety <duration>;
signatures-jitter <duration>;
signatures-refresh <duration>;
signatures-validity <duration>;
signatures-validity-dnskey <duration>;
zone-propagation-delay <duration>;
}; // may occur multiple times
dyndb <string> <quoted_string> { <unspecified-text> }; // may occur multiple times
http <string> {
endpoints { <quoted_string>; ... };
listener-clients <integer>;
streams-per-connection <integer>;
}; // may occur multiple times
key <string> {
algorithm <string>;
secret <string>;
}; // may occur multiple times
logging {
category <string> { <string>; ... }; // may occur multiple times
channel <string> {
buffered <boolean>;
file <quoted_string> [ versions ( unlimited | <integer> ) ] [ size <size> ] [ suffix ( increment | timestamp ) ];
null;
print-category <boolean>;
print-severity <boolean>;
print-time ( iso8601 | iso8601-utc | local | <boolean> );
severity <log_severity>;
stderr;
syslog [ <syslog_facility> ];
}; // may occur multiple times
};
managed-keys { <string> ( static-key | initial-key | static-ds | initial-ds ) <integer> <integer> <integer> <quoted_string>; ... }; // may occur multiple times, deprecated
options {
allow-new-zones <boolean>;
allow-notify { <address_match_element>; ... };
allow-query { <address_match_element>; ... };
allow-query-cache { <address_match_element>; ... };
allow-query-cache-on { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
allow-recursion { <address_match_element>; ... };
allow-recursion-on { <address_match_element>; ... };
allow-transfer [ port <integer> ] [ transport <string> ] { <address_match_element>; ... };
allow-update { <address_match_element>; ... };
allow-update-forwarding { <address_match_element>; ... };
also-notify [ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
alt-transfer-source ( <ipv4_address> | * ) ; // deprecated
alt-transfer-source-v6 ( <ipv6_address> | * ) ; // deprecated
answer-cookie <boolean>;
attach-cache <string>;
auth-nxdomain <boolean>;
auto-dnssec ( allow | maintain | off ) ; // deprecated
automatic-interface-scan <boolean>;
avoid-v4-udp-ports { <portrange>; ... }; // deprecated
avoid-v6-udp-ports { <portrange>; ... }; // deprecated
bindkeys-file <quoted_string>;
blackhole { <address_match_element>; ... };
catalog-zones { zone <string> [ default-primaries [ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... } ] [ zone-directory <quoted_string> ] [ in-memory <boolean> ] [ min-update-interval <duration> ]; ... };
check-dup-records ( fail | warn | ignore );
check-integrity <boolean>;
check-mx ( fail | warn | ignore );
check-mx-cname ( fail | warn | ignore );
check-names ( primary | master | secondary | slave | response ) ( fail | warn | ignore ); // may occur multiple times
check-sibling <boolean>;
check-spf ( warn | ignore );
check-srv-cname ( fail | warn | ignore );
check-wildcard <boolean>;
clients-per-query <integer>;
cookie-algorithm ( aes | siphash24 );
cookie-secret <string>; // may occur multiple times
coresize ( default | unlimited | <sizeval> ); // deprecated
datasize ( default | unlimited | <sizeval> ); // deprecated
deny-answer-addresses { <address_match_element>; ... } [ except-from { <string>; ... } ];
deny-answer-aliases { <string>; ... } [ except-from { <string>; ... } ];
dialup ( notify | notify-passive | passive | refresh | <boolean> ); // deprecated
directory <quoted_string>;
disable-algorithms <string> { <string>; ... }; // may occur multiple times
disable-ds-digests <string> { <string>; ... }; // may occur multiple times
disable-empty-zone <string>; // may occur multiple times
dns64 <netprefix> {
break-dnssec <boolean>;
clients { <address_match_element>; ... };
exclude { <address_match_element>; ... };
mapped { <address_match_element>; ... };
recursive-only <boolean>;
suffix <ipv6_address>;
}; // may occur multiple times
dns64-contact <string>;
dns64-server <string>;
dnskey-sig-validity <integer>;
dnsrps-enable <boolean>; // not configured
dnsrps-options { <unspecified-text> }; // not configured
dnssec-accept-expired <boolean>;
dnssec-dnskey-kskonly <boolean>;
dnssec-loadkeys-interval <integer>;
dnssec-must-be-secure <string> <boolean>; // may occur multiple times, deprecated
dnssec-policy <string>;
dnssec-secure-to-insecure <boolean>;
dnssec-update-mode ( maintain | no-resign );
dnssec-validation ( yes | no | auto );
dnstap { ( all | auth | client | forwarder | resolver | update ) [ ( query | response ) ]; ... }; // not configured
dnstap-identity ( <quoted_string> | none | hostname ); // not configured
dnstap-output ( file | unix ) <quoted_string> [ size ( unlimited | <size> ) ] [ versions ( unlimited | <integer> ) ] [ suffix ( increment | timestamp ) ]; // not configured
dnstap-version ( <quoted_string> | none ); // not configured
dscp <integer>; // obsolete
dual-stack-servers [ port <integer> ] { ( <quoted_string> [ port <integer> ] | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ); ... };
dump-file <quoted_string>;
edns-udp-size <integer>;
empty-contact <string>;
empty-server <string>;
empty-zones-enable <boolean>;
fetch-quota-params <integer> <fixedpoint> <fixedpoint> <fixedpoint>;
fetches-per-server <integer> [ ( drop | fail ) ];
fetches-per-zone <integer> [ ( drop | fail ) ];
files ( default | unlimited | <sizeval> ); // deprecated
flush-zones-on-shutdown <boolean>;
forward ( first | only );
forwarders [ port <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ]; ... };
fstrm-set-buffer-hint <integer>; // not configured
fstrm-set-flush-timeout <integer>; // not configured
fstrm-set-input-queue-size <integer>; // not configured
fstrm-set-output-notify-threshold <integer>; // not configured
fstrm-set-output-queue-model ( mpscs | spscs ); // not configured
fstrm-set-output-queue-size <integer>; // not configured
fstrm-set-reopen-interval <duration>; // not configured
geoip-directory ( <quoted_string> | none );
glue-cache <boolean>; // deprecated
heartbeat-interval <integer>; // deprecated
hostname ( <quoted_string> | none );
http-listener-clients <integer>;
http-port <integer>;
http-streams-per-connection <integer>;
https-port <integer>;
interface-interval <duration>;
ipv4only-contact <string>;
ipv4only-enable <boolean>;
ipv4only-server <string>;
ixfr-from-differences ( primary | master | secondary | slave | <boolean> );
keep-response-order { <address_match_element>; ... };
key-directory <quoted_string>;
lame-ttl <duration>;
listen-on [ port <integer> ] [ tls <string> ] [ http <string> ] { <address_match_element>; ... }; // may occur multiple times
listen-on-v6 [ port <integer> ] [ tls <string> ] [ http <string> ] { <address_match_element>; ... }; // may occur multiple times
lmdb-mapsize <sizeval>;
lock-file ( <quoted_string> | none );
managed-keys-directory <quoted_string>;
masterfile-format ( raw | text );
masterfile-style ( full | relative );
match-mapped-addresses <boolean>;
max-cache-size ( default | unlimited | <sizeval> | <percentage> );
max-cache-ttl <duration>;
max-clients-per-query <integer>;
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-ncache-ttl <duration>;
max-query-count <integer>;
max-query-restarts <integer>;
max-records <integer>;
max-records-per-type <integer>;
max-recursion-depth <integer>;
max-recursion-queries <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-rsa-exponent-size <integer>;
max-stale-ttl <duration>;
max-transfer-idle-in <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
max-types-per-name <integer>;
max-udp-size <integer>;
maxz-zone-ttl ( unlimited | <duration> );
memstatistics <boolean>;
memstatistics-file <quoted_string>;
message-compression <boolean>;
min-cache-ttl <duration>;
min-ncache-ttl <duration>;
min-refresh-time <integer>;
min-retry-time <integer>;
minimal-any <boolean>;
minimal-responses ( no-auth | no-auth-recursive | <boolean> );
multi-master <boolean>;
new-zones-directory <quoted_string>;
no-case-compress { <address_match_element>; ... };
nocookie-udp-size <integer>;
notify ( explicit | master-only | primary-only | <boolean> );
notify-delay <integer>;
notify-rate <integer>;
notify-source ( <ipv4_address> | * ) ;
notify-source-v6 ( <ipv6_address> | * ) ;
notify-to-soa <boolean>;
nsec3-test-zone <boolean>; // test only
nta-lifetime <duration>;
nta-recheck <duration>;
nxdomain-redirect <string>;
parental-source ( <ipv4_address> | * ) ;
parental-source-v6 ( <ipv6_address> | * ) ;
pid-file ( <quoted_string> | none );
port <integer>;
preferred-glue <string>;
prefetch <integer> [ <integer> ];
provide-ixfr <boolean>;
qname-minimization ( strict | relaxed | disabled | off );
query-source [ address ] ( <ipv4_address> | * );
query-source-v6 [ address ] ( <ipv6_address> | * );
querylog <boolean>;
random-device ( <quoted_string> | none ); // obsolete
rate-limit {
all-per-second <integer>;
errors-per-second <integer>;
exempt-clients { <address_match_element>; ... };
ipv4-prefix-length <integer>;
ipv6-prefix-length <integer>;
log-only <boolean>;
max-table-size <integer>;
min-table-size <integer>;
nodata-per-second <integer>;
nxdomains-per-second <integer>;
qps-scale <integer>;
referrals-per-second <integer>;
responses-per-second <integer>;
slip <integer>;
window <integer>;
};
recurse-ing-file <quoted_string>;
recursion <boolean>;
recursive-clients <integer>;
request-expire <boolean>;
request-ixfr <boolean>;
request-nsid <boolean>;
require-server-cookie <boolean>;
reserved-sockets <integer>; // deprecated
resolver-nonbackoff-tries <integer>; // deprecated
resolver-query-timeout <integer>;
resolver-retry-interval <integer>; // deprecated
response-padding { <address_match_element>; ... } block-size <integer>;
response-policy { zone <string> [ add-soa <boolean> ] [ log <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only <quoted_string> ) ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ]; ... } [ add-soa <boolean> ] [ break-dnssec <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ min-ns-dots <integer> ] [ nsip-wait-recurse <boolean> ] [ nsdname-wait-recurse <boolean> ] [ qname-wait-recurse <boolean> ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ dnsrps-enable <boolean> ] [ dnsrps-options { <unspecified-text> } ];
reuse port <boolean>;
root-delegation-only [ exclude { <string>; ... } ]; // deprecated
root-key-sentinel <boolean>;
rrset-order { [ class <string> ] [ type <string> ] [ name <quoted_string> ] <string> <string>; ... };
secroots-file <quoted_string>;
send-cookie <boolean>;
serial-query-rate <integer>;
serial-update-method ( date | increment | unixtime );
server-id ( <quoted_string> | none | hostname );
servfail-ttl <duration>;
session-keyalg <string>;
session-keyfile ( <quoted_string> | none );
session-keyname <string>;
sig-signing-nodes <integer>;
sig-signing-signatures <integer>;
sig-signing-type <integer>;
sig-validity-interval <integer> [ <integer> ];
sortlist { <address_match_element>; ... };
stacksize ( default | unlimited | <sizeval> ); // deprecated
stale-answer-client-timeout ( disabled | off | <integer> );
stale-answer-enable <boolean>;
stale-answer-ttl <duration>;
stale-cache-enable <boolean>;
stale-refresh-time <duration>;
startup-notify-rate <integer>;
statistics-file <quoted_string>;
suppress-initial-notify <boolean>; // obsolete
synth-from-dnssec <boolean>;
tcp-advertised-timeout <integer>;
tcp-clients <integer>;
tcp-idle-timeout <integer>;
tcp-initial-timeout <integer>;
tcp-keepalive-timeout <integer>;
tcp-listen-queue <integer>;
tcp-receive-buffer <integer>;
tcp-send-buffer <integer>;
tkey-dhkey <quoted_string> <integer>; // deprecated
tkey-domain <quoted_string>; // deprecated
tkey-gssapi-credential <quoted_string>; // deprecated
tkey-gssapi-keytab <quoted_string>;
tls-port <integer>;
transfer-format ( many-answers | one-answer );
transfer-message-size <integer>;
transfer-source ( <ipv4_address> | * ) ;
transfer-source-v6 ( <ipv6_address> | * ) ;
transfers-in <integer>;
transfers-out <integer>;
transfers-per-ns <integer>;
trust-anchor-telemetry <boolean>;
try-tcp-refresh <boolean>;
udp-receive-buffer <integer>;
udp-send-buffer <integer>;
update-check-ksk <boolean>;
update-quota <integer>;
use-alt-transfer-source <boolean>; // deprecated
use-v4-udp-ports { <portrange>; ... }; // deprecated
use-v6-udp-ports { <portrange>; ... }; // deprecated
v6-bias <integer>;
validate-except { <string>; ... };
version ( <quoted_string> | none );
zero-no-soa-ttl <boolean>;
zero-no-soa-ttl-cache <boolean>;
zone-statistics ( full | terse | none | <boolean> );
};
parental-agents <string> [ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... }; // may occur multiple times
plugin ( query ) <string> [ { <unspecified-text> } ]; // may occur multiple times
primaries <string> [ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... }; // may occur multiple times
server <netprefix> {
bogus <boolean>;
edns <boolean>;
edns-udp-size <integer>;
edns-version <integer>;
keys <server_key>;
max-udp-size <integer>;
notify-source ( <ipv4_address> | * ) ;
notify-source-v6 ( <ipv6_address> | * ) ;
padding <integer>;
provide-ixfr <boolean>;
query-source [ address ] ( <ipv4_address> | * );
query-source-v6 [ address ] ( <ipv6_address> | * );
request-expire <boolean>;
request-ixfr <boolean>;
request-nsid <boolean>;
send-cookie <boolean>;
tcp-keepalive <boolean>;
tcp-only <boolean>;
transfer-format ( many-answers | one-answer );
transfer-source ( <ipv4_address> | * ) ;
transfer-source-v6 ( <ipv6_address> | * ) ;
transfers <integer>;
}; // may occur multiple times
statistics-channels {
inet ( <ipv4_address> | <ipv6_address> | * ) [ port ( <integer> | * ) ] [ allow { <address_match_element>; ... } ]; // may occur multiple times
}; // may occur multiple times
tls <string> {
ca-file <quoted_string>;
cert-file <quoted_string>;
ciphers <string>;
dhparam-file <quoted_string>;
key-file <quoted_string>;
prefer-server-ciphers <boolean>;
protocols { <string>; ... };
remote-hostname <quoted_string>;
session-tickets <boolean>;
}; // may occur multiple times
trust-anchors { <string> ( static-key | initial-key | static-ds | initial-ds ) <integer> <integer> <integer> <quoted_string>; ... }; // may occur multiple times
trusted-keys { <string> <integer> <integer> <integer> <quoted_string>; ... }; // may occur multiple times, deprecated
view <string> [ <class> ] {
allow-new-zones <boolean>;
allow-notify { <address_match_element>; ... };
allow-query { <address_match_element>; ... };
allow-query-cache { <address_match_element>; ... };
allow-query-cache-on { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
allow-recursion { <address_match_element>; ... };
allow-recursion-on { <address_match_element>; ... };
allow-transfer [ port <integer> ] [ transport <string> ] { <address_match_element>; ... };
allow-update { <address_match_element>; ... };
allow-update-forwarding { <address_match_element>; ... };
also-notify [ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
alt-transfer-source ( <ipv4_address> | * ) ; // deprecated
alt-transfer-source-v6 ( <ipv6_address> | * ) ; // deprecated
attach-cache <string>;
auth-nxdomain <boolean>;
auto-dnssec ( allow | maintain | off ) ; // deprecated
catalog-zones { zone <string> [ default-primaries [ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... } ] [ zone-directory <quoted_string> ] [ in-memory <boolean> ] [ min-update-interval <duration> ]; ... };
check-dup-records ( fail | warn | ignore );
check-integrity <boolean>;
check-mx ( fail | warn | ignore );
check-mx-cname ( fail | warn | ignore );
check-names ( primary | master | secondary | slave | response ) ( fail | warn | ignore ); // may occur multiple times
check-sibling <boolean>;
check-spf ( warn | ignore );
check-srv-cname ( fail | warn | ignore );
check-wildcard <boolean>;
clients-per-query <integer>;
deny-answer-addresses { <address_match_element>; ... } [ except-from { <string>; ... } ];
deny-answer-aliases { <string>; ... } [ except-from { <string>; ... } ];
dialup ( notify | notify-passive | passive | refresh | <boolean> ); // deprecated
disable-algorithms <string> { <string>; ... }; // may occur multiple times
disable-ds-digests <string> { <string>; ... }; // may occur multiple times
disable-empty-zone <string>; // may occur multiple times
dlz <string> {
database <string>;
search <boolean>;
}; // may occur multiple times
dns64 <netprefix> {
break-dnssec <boolean>;
clients { <address_match_element>; ... };
exclude { <address_match_element>; ... };
mapped { <address_match_element>; ... };
recursive-only <boolean>;
suffix <ipv6_address>;
}; // may occur multiple times
dns64-contact <string>;
dns64-server <string>;
dnskey-sig-validity <integer>;
dnsrps-enable <boolean>; // not configured
dnsrps-options { <unspecified-text> }; // not configured
dnssec-accept-expired <boolean>;
dnssec-dnskey-kskonly <boolean>;
dnssec-loadkeys-interval <integer>;
dnssec-must-be-secure <string> <boolean>; // may occur multiple times, deprecated
dnssec-policy <string>;
dnssec-secure-to-insecure <boolean>;
dnssec-update-mode ( maintain | no-resign );
dnssec-validation ( yes | no | auto );
dnstap { ( all | auth | client | forwarder | resolver | update ) [ ( query | response ) ]; ... }; // not configured
dual-stack-servers [ port <integer> ] { ( <quoted_string> [ port <integer> ] | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ); ... };
dyndb <string> <quoted_string> { <unspecified-text> }; // may occur multiple times
edns-udp-size <integer>;
empty-contact <string>;
empty-server <string>;
empty-zones-enable <boolean>;
fetch-quota-params <integer> <fixedpoint> <fixedpoint> <fixedpoint>;
fetches-per-server <integer> [ ( drop | fail ) ];
fetches-per-zone <integer> [ ( drop | fail ) ];
forward ( first | only );
forwarders [ port <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ]; ... };
glue-cache <boolean>; // deprecated
ipv4only-contact <string>;
ipv4only-enable <boolean>;
ipv4only-server <string>;
ixfr-from-differences ( primary | master | secondary | slave | <boolean> );
key <string> {
algorithm <string>;
secret <string>;
}; // may occur multiple times
key-directory <quoted_string>;
lame-ttl <duration>;
lmdb-mapsize <sizeval>;
masterfile-format ( raw | text );
masterfile-style ( full | relative );
match-clients { <address_match_element>; ... };
match-destinations { <address_match_element>; ... };
match-recursive-only <boolean>;
max-cache-size ( default | unlimited | <sizeval> | <percentage> );
max-cache-ttl <duration>;
max-clients-per-query <integer>;
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-ncache-ttl <duration>;
max-query-count <integer>;
max-query-restarts <integer>;
max-records <integer>;
max-records-per-type <integer>;
max-recursion-depth <integer>;
max-recursion-queries <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-stale-ttl <duration>;
max-transfer-idle-in <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
max-types-per-name <integer>;
max-udp-size <integer>;
maxz-zone-ttl ( unlimited | <duration> );
message-compression <boolean>;
min-cache-ttl <duration>;
min-ncache-ttl <duration>;
min-refresh-time <integer>;
min-retry-time <integer>;
minimal-any <boolean>;
minimal-responses ( no-auth | no-auth-recursive | <boolean> );
multi-master <boolean>;
new-zones-directory <quoted_string>;
no-case-compress { <address_match_element>; ... };
nocookie-udp-size <integer>;
notify ( explicit | master-only | primary-only | <boolean> );
notify-delay <integer>;
notify-source ( <ipv4_address> | * ) ;
notify-source-v6 ( <ipv6_address> | * ) ;
notify-to-soa <boolean>;
nsec3-test-zone <boolean>; // test only
nta-lifetime <duration>;
nta-recheck <duration>;
nxdomain-redirect <string>;
parental-source ( <ipv4_address> | * ) ;
parental-source-v6 ( <ipv6_address> | * ) ;
plugin ( query ) <string> [ { <unspecified-text> } ]; // may occur multiple times
preferred-glue <string>;
prefetch <integer> [ <integer> ];
provide-ixfr <boolean>;
qname-minimization ( strict | relaxed | disabled | off );
query-source [ address ] ( <ipv4_address> | * );
query-source-v6 [ address ] ( <ipv6_address> | * );
rate-limit {
all-per-second <integer>;
errors-per-second <integer>;
exempt-clients { <address_match_element>; ... };
ipv4-prefix-length <integer>;
ipv6-prefix-length <integer>;
log-only <boolean>;
max-table-size <integer>;
min-table-size <integer>;
nodata-per-second <integer>;
nxdomains-per-second <integer>;
qps-scale <integer>;
referrals-per-second <integer>;
responses-per-second <integer>;
slip <integer>;
window <integer>;
};
recursion <boolean>;
request-expire <boolean>;
request-ixfr <boolean>;
request-nsid <boolean>;
require-server-cookie <boolean>;
resolver-nonbackoff-tries <integer>; // deprecated
resolver-query-timeout <integer>;
resolver-retry-interval <integer>; // deprecated
response-padding { <address_match_element>; ... } block-size <integer>;
response-policy { zone <string> [ add-soa <boolean> ] [ log <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only <quoted_string> ) ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ]; ... } [ add-soa <boolean> ] [ break-dnssec <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ min-ns-dots <integer> ] [ nsip-wait-recurse <boolean> ] [ nsdname-wait-recurse <boolean> ] [ qname-wait-recurse <boolean> ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ dnsrps-enable <boolean> ] [ dnsrps-options { <unspecified-text> } ];
root-delegation-only [ exclude { <string>; ... } ]; // deprecated
root-key-sentinel <boolean>;
rrset-order { [ class <string> ] [ type <string> ] [ name <quoted_string> ] <string> <string>; ... };
send-cookie <boolean>;
serial-update-method ( date | increment | unixtime );
server <netprefix> {
bogus <boolean>;
edns <boolean>;
edns-udp-size <integer>;
edns-version <integer>;
keys <server_key>;
max-udp-size <integer>;
notify-source ( <ipv4_address> | * ) ;
notify-source-v6 ( <ipv6_address> | * ) ;
padding <integer>;
provide-ixfr <boolean>;
query-source [ address ] ( <ipv4_address> | * );
query-source-v6 [ address ] ( <ipv6_address> | * );
request-expire <boolean>;
request-ixfr <boolean>;
request-nsid <boolean>;
send-cookie <boolean>;
tcp-keepalive <boolean>;
tcp-only <boolean>;
transfer-format ( many-answers | one-answer );
transfer-source ( <ipv4_address> | * ) ;
transfer-source-v6 ( <ipv6_address> | * ) ;
transfers <integer>;
}; // may occur multiple times
servfail-ttl <duration>;
sig-signing-nodes <integer>;
sig-signing-signatures <integer>;
sig-signing-type <integer>;
sig-validity-interval <integer> [ <integer> ];
sortlist { <address_match_element>; ... };
stale-answer-client-timeout ( disabled | off | <integer> );
stale-answer-enable <boolean>;
stale-answer-ttl <duration>;
stale-cache-enable <boolean>;
stale-refresh-time <duration>;
suppress-initial-notify <boolean>; // obsolete
synth-from-dnssec <boolean>;
transfer-format ( many-answers | one-answer );
transfer-source ( <ipv4_address> | * ) ;
transfer-source-v6 ( <ipv6_address> | * ) ;
trust-anchor-telemetry <boolean>;
trust-anchors { <string> ( static-key | initial-key | static-ds | initial-ds ) <integer> <integer> <integer> <quoted_string>; ... }; // may occur multiple times
trusted-keys { <string> <integer> <integer> <integer> <quoted_string>; ... }; // may occur multiple times, deprecated
try-tcp-refresh <boolean>;
update-check-ksk <boolean>;
use-alt-transfer-source <boolean>; // deprecated
v6-bias <integer>;
validate-except { <string>; ... };
zero-no-soa-ttl <boolean>;
zero-no-soa-ttl-cache <boolean>;
zone-statistics ( full | terse | none | <boolean> );
}; // may occur multiple times

View File

@@ -0,0 +1,64 @@
zone <string> [ <class> ] {
type primary;
allow-query { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
allow-transfer [ port <integer> ] [ transport <string> ] { <address_match_element>; ... };
allow-update { <address_match_element>; ... };
also-notify [ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
alt-transfer-source ( <ipv4_address> | * ) ; // deprecated
alt-transfer-source-v6 ( <ipv6_address> | * ) ; // deprecated
auto-dnssec ( allow | maintain | off ) ; // deprecated
check-dup-records ( fail | warn | ignore );
check-integrity <boolean>;
check-mx ( fail | warn | ignore );
check-mx-cname ( fail | warn | ignore );
check-names ( fail | warn | ignore );
check-sibling <boolean>;
check-spf ( warn | ignore );
check-srv-cname ( fail | warn | ignore );
check-wildcard <boolean>;
database <string>;
dialup ( notify | notify-passive | passive | refresh | <boolean> ); // deprecated
dlz <string>;
dnskey-sig-validity <integer>;
dnssec-dnskey-kskonly <boolean>;
dnssec-loadkeys-interval <integer>;
dnssec-policy <string>;
dnssec-secure-to-insecure <boolean>;
dnssec-update-mode ( maintain | no-resign );
file <quoted_string>;
forward ( first | only );
forwarders [ port <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ]; ... };
inline-signing <boolean>;
ixfr-from-differences <boolean>;
journal <quoted_string>;
key-directory <quoted_string>;
masterfile-format ( raw | text );
masterfile-style ( full | relative );
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
max-records-per-type <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-out <integer>;
max-types-per-name <integer>;
max-zone-ttl ( unlimited | <duration> );
notify ( explicit | master-only | primary-only | <boolean> );
notify-delay <integer>;
notify-source ( <ipv4_address> | * ) ;
notify-source-v6 ( <ipv6_address> | * ) ;
notify-to-soa <boolean>;
nsec3-test-zone <boolean>; // test only
parental-agents [ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
parental-source ( <ipv4_address> | * ) ;
parental-source-v6 ( <ipv6_address> | * ) ;
serial-update-method ( date | increment | unixtime );
sig-signing-nodes <integer>;
sig-signing-signatures <integer>;
sig-signing-type <integer>;
sig-validity-interval <integer> [ <integer> ];
update-check-ksk <boolean>;
update-policy ( local | { ( deny | grant ) <string> ( 6to4-self | external | krb5-self | krb5-selfsub | krb5-subdomain | krb5-subdomain-self-rhs | ms-self | ms-selfsub | ms-subdomain | ms-subdomain-self-rhs | name | self | selfsub | selfwild | subdomain | tcp-self | wildcard | zonesubject ) [ <string> ] <rrtype list>; ... } );
zero-no-soa-ttl <boolean>;
zone-statistics ( full | terse | none | <boolean> );
};

View File

@@ -0,0 +1,15 @@
zone <string> [ <class> ] {
type redirect;
allow-query { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
dlz <string>;
file <quoted_string>;
masterfile-format ( raw | text );
masterfile-style ( full | relative );
max-records <integer>;
max-records-per-type <integer>;
max-types-per-name <integer>;
max-zone-ttl ( unlimited | <duration> );
primaries [ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
zone-statistics ( full | terse | none | <boolean> );
};

View File

@@ -0,0 +1,20 @@
key <string> {
algorithm <string>;
secret <string>;
}; // may occur multiple times
options {
default-key <string>;
default-port <integer>;
default-server <string>;
default-source-address ( <ipv4_address> | * );
default-source-address-v6 ( <ipv6_address> | * );
};
server <string> {
addresses { ( <quoted_string> [ port <integer> ] | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ); ... };
key <string>;
port <integer>;
source-address ( <ipv4_address> | * );
source-address-v6 ( <ipv6_address> | * );
}; // may occur multiple times

View File

@@ -0,0 +1,67 @@
zone <string> [ <class> ] {
type secondary;
allow-notify { <address_match_element>; ... };
allow-query { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
allow-transfer [ port <integer> ] [ transport <string> ] { <address_match_element>; ... };
allow-update-forwarding { <address_match_element>; ... };
also-notify [ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
alt-transfer-source ( <ipv4_address> | * ) ; // deprecated
alt-transfer-source-v6 ( <ipv6_address> | * ) ; // deprecated
auto-dnssec ( allow | maintain | off ) ; // deprecated
check-names ( fail | warn | ignore );
database <string>;
dialup ( notify | notify-passive | passive | refresh | <boolean> ); // deprecated
dlz <string>;
dnskey-sig-validity <integer>;
dnssec-dnskey-kskonly <boolean>;
dnssec-loadkeys-interval <integer>;
dnssec-policy <string>;
dnssec-update-mode ( maintain | no-resign );
file <quoted_string>;
forward ( first | only );
forwarders [ port <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ]; ... };
inline-signing <boolean>;
ixfr-from-differences <boolean>;
journal <quoted_string>;
key-directory <quoted_string>;
masterfile-format ( raw | text );
masterfile-style ( full | relative );
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
max-records-per-type <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
max-types-per-name <integer>;
min-refresh-time <integer>;
min-retry-time <integer>;
multi-master <boolean>;
notify ( explicit | master-only | primary-only | <boolean> );
notify-delay <integer>;
notify-source ( <ipv4_address> | * ) ;
notify-source-v6 ( <ipv6_address> | * ) ;
notify-to-soa <boolean>;
nsec3-test-zone <boolean>; // test only
parental-agents [ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
parental-source ( <ipv4_address> | * ) ;
parental-source-v6 ( <ipv6_address> | * ) ;
primaries [ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
request-expire <boolean>;
request-ixfr <boolean>;
sig-signing-nodes <integer>;
sig-signing-signatures <integer>;
sig-signing-type <integer>;
sig-validity-interval <integer> [ <integer> ];
transfer-source ( <ipv4_address> | * ) ;
transfer-source-v6 ( <ipv6_address> | * ) ;
try-tcp-refresh <boolean>;
update-check-ksk <boolean>;
use-alt-transfer-source <boolean>; // deprecated
zero-no-soa-ttl <boolean>;
zone-statistics ( full | terse | none | <boolean> );
};

View File

@@ -0,0 +1,13 @@
zone <string> [ <class> ] {
type static-stub;
allow-query { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
forward ( first | only );
forwarders [ port <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ]; ... };
max-records <integer>;
max-records-per-type <integer>;
max-types-per-name <integer>;
server-addresses { ( <ipv4_address> | <ipv6_address> ); ... };
server-names { <string>; ... };
zone-statistics ( full | terse | none | <boolean> );
};

View File

@@ -0,0 +1,29 @@
zone <string> [ <class> ] {
type stub;
allow-query { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
check-names ( fail | warn | ignore );
database <string>;
delegation-only <boolean>; // deprecated
dialup ( notify | notify-passive | passive | refresh | <boolean> ); // deprecated
file <quoted_string>;
forward ( first | only );
forwarders [ port <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ]; ... };
masterfile-format ( raw | text );
masterfile-style ( full | relative );
max-records <integer>;
max-records-per-type <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
max-transfer-time-in <integer>;
max-types-per-name <integer>;
min-refresh-time <integer>;
min-retry-time <integer>;
multi-master <boolean>;
primaries [ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
transfer-source ( <ipv4_address> | * ) ;
transfer-source-v6 ( <ipv6_address> | * ) ;
use-alt-transfer-source <boolean>; // deprecated
zone-statistics ( full | terse | none | <boolean> );
};

View File

@@ -0,0 +1,5 @@
zone <string> [ <class> ] {
type forward;
forward ( first | only );
forwarders [ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... };
};

View File

@@ -0,0 +1,5 @@
zone <string> [ <class> ] {
type hint;
check-names ( fail | warn | ignore );
file <quoted_string>;
};

View File

@@ -0,0 +1,3 @@
zone <string> [ <class> ] {
in-view <string>;
};

View File

@@ -0,0 +1,44 @@
zone <string> [ <class> ] {
type mirror;
allow-notify { <address_match_element>; ... };
allow-query { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
allow-transfer [ port <integer> ] [ transport <string> ] { <address_match_element>; ... };
allow-update-forwarding { <address_match_element>; ... };
also-notify [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
check-names ( fail | warn | ignore );
database <string>;
file <quoted_string>;
ixfr-from-differences <boolean>;
journal <quoted_string>;
masterfile-format ( raw | text );
masterfile-style ( full | relative );
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
max-records-per-type <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
max-types-per-name <integer>;
min-refresh-time <integer>;
min-retry-time <integer>;
min-transfer-rate-in <integer> <integer>;
multi-master <boolean>;
notify ( explicit | master-only | primary-only | <boolean> );
notify-defer <integer>;
notify-delay <integer>;
notify-source ( <ipv4_address> | * ) ;
notify-source-v6 ( <ipv6_address> | * ) ;
primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
request-expire <boolean>;
request-ixfr <boolean>;
transfer-source ( <ipv4_address> | * ) ;
transfer-source-v6 ( <ipv6_address> | * ) ;
try-tcp-refresh <boolean>;
zero-no-soa-ttl <boolean>;
zone-statistics ( full | terse | none | <boolean> );
};

View File

@@ -0,0 +1,605 @@
acl <string> { <address_match_element>; ... }; // may occur multiple times
controls {
inet ( <ipv4_address> | <ipv6_address> | * ) [ port ( <integer> | * ) ] allow { <address_match_element>; ... } [ keys { <string>; ... } ] [ read-only <boolean> ]; // may occur multiple times
unix <quoted_string> perm <integer> owner <integer> group <integer> [ keys { <string>; ... } ] [ read-only <boolean> ]; // may occur multiple times
}; // may occur multiple times
dlz <string> {
database <string>;
search <boolean>;
}; // may occur multiple times
dnssec-policy <string> {
cdnskey <boolean>;
cds-digest-types { <string>; ... };
dnskey-ttl <duration>;
inline-signing <boolean>;
keys { ( csk | ksk | zsk ) [ key-directory | key-store <string> ] lifetime <duration_or_unlimited> algorithm <string> [ tag-range <integer> <integer> ] [ <integer> ]; ... };
manual-mode <boolean>;
max-zone-ttl <duration>;
nsec3param [ iterations <integer> ] [ optout <boolean> ] [ salt-length <integer> ];
offline-ksk <boolean>;
parent-ds-ttl <duration>;
parent-propagation-delay <duration>;
publish-safety <duration>;
purge-keys <duration>;
retire-safety <duration>;
signatures-jitter <duration>;
signatures-refresh <duration>;
signatures-validity <duration>;
signatures-validity-dnskey <duration>;
zone-propagation-delay <duration>;
}; // may occur multiple times
dyndb <string> <quoted_string> { <unspecified-text> }; // may occur multiple times
http <string> {
endpoints { <quoted_string>; ... };
listener-clients <integer>;
streams-per-connection <integer>;
}; // may occur multiple times
key <string> {
algorithm <string>;
secret <string>;
}; // may occur multiple times
key-store <string> {
directory <string>;
pkcs11-uri <quoted_string>;
}; // may occur multiple times
logging {
category <string> { <string>; ... }; // may occur multiple times
channel <string> {
buffered <boolean>;
file <quoted_string> [ versions ( unlimited | <integer> ) ] [ size <size> ] [ suffix ( increment | timestamp ) ];
null;
print-category <boolean>;
print-severity <boolean>;
print-time ( iso8601 | iso8601-utc | local | <boolean> );
severity <log_severity>;
stderr;
syslog [ <syslog_facility> ];
}; // may occur multiple times
};
managed-keys { <string> ( static-key | initial-key | static-ds | initial-ds ) <integer> <integer> <integer> <quoted_string>; ... }; // may occur multiple times, deprecated
options {
allow-new-zones <boolean>;
allow-notify { <address_match_element>; ... };
allow-proxy { <address_match_element>; ... }; // experimental
allow-proxy-on { <address_match_element>; ... }; // experimental
allow-query { <address_match_element>; ... };
allow-query-cache { <address_match_element>; ... };
allow-query-cache-on { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
allow-recursion { <address_match_element>; ... };
allow-recursion-on { <address_match_element>; ... };
allow-transfer [ port <integer> ] [ transport <string> ] { <address_match_element>; ... };
allow-update { <address_match_element>; ... };
allow-update-forwarding { <address_match_element>; ... };
also-notify [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
answer-cookie <boolean>;
attach-cache <string>;
auth-nxdomain <boolean>;
automatic-interface-scan <boolean>;
avoid-v4-udp-ports { <portrange>; ... }; // deprecated
avoid-v6-udp-ports { <portrange>; ... }; // deprecated
bindkeys-file <quoted_string>; // test only
blackhole { <address_match_element>; ... };
catalog-zones { zone <string> [ default-primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... } ] [ zone-directory <quoted_string> ] [ in-memory <boolean> ] [ min-update-interval <duration> ]; ... };
check-dup-records ( fail | warn | ignore );
check-integrity <boolean>;
check-mx ( fail | warn | ignore );
check-mx-cname ( fail | warn | ignore );
check-names ( primary | master | secondary | slave | response ) ( fail | warn | ignore ); // may occur multiple times
check-sibling <boolean>;
check-spf ( warn | ignore );
check-srv-cname ( fail | warn | ignore );
check-svcb <boolean>;
check-wildcard <boolean>;
clients-per-query <integer>;
cookie-algorithm ( siphash24 );
cookie-secret <string>; // may occur multiple times
deny-answer-addresses { <address_match_element>; ... } [ except-from { <string>; ... } ];
deny-answer-aliases { <string>; ... } [ except-from { <string>; ... } ];
dialup ( notify | notify-passive | passive | refresh | <boolean> ); // deprecated
directory <quoted_string>;
disable-algorithms <string> { <string>; ... }; // may occur multiple times
disable-ds-digests <string> { <string>; ... }; // may occur multiple times
disable-empty-zone <string>; // may occur multiple times
dns64 <netprefix> {
break-dnssec <boolean>;
clients { <address_match_element>; ... };
exclude { <address_match_element>; ... };
mapped { <address_match_element>; ... };
recursive-only <boolean>;
suffix <ipv6_address>;
}; // may occur multiple times
dns64-contact <string>;
dns64-server <string>;
dnskey-sig-validity <integer>; // obsolete
dnsrps-enable <boolean>; // not configured
dnsrps-library <quoted_string>; // not configured
dnsrps-options { <unspecified-text> }; // not configured
dnssec-accept-expired <boolean>;
dnssec-dnskey-kskonly <boolean>; // obsolete
dnssec-loadkeys-interval <integer>;
dnssec-must-be-secure <string> <boolean>; // may occur multiple times, deprecated
dnssec-policy <string>;
dnssec-secure-to-insecure <boolean>; // obsolete
dnssec-update-mode ( maintain | no-resign ) ; // obsolete
dnssec-validation ( yes | no | auto );
dnstap { ( all | auth | client | forwarder | resolver | update ) [ ( query | response ) ]; ... }; // not configured
dnstap-identity ( <quoted_string> | none | hostname ); // not configured
dnstap-output ( file | unix ) <quoted_string> [ size ( unlimited | <size> ) ] [ versions ( unlimited | <integer> ) ] [ suffix ( increment | timestamp ) ]; // not configured
dnstap-version ( <quoted_string> | none ); // not configured
dual-stack-servers [ port <integer> ] { ( <quoted_string> [ port <integer> ] | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ); ... };
dump-file <quoted_string>;
edns-udp-size <integer>;
empty-contact <string>;
empty-server <string>;
empty-zones-enable <boolean>;
fetch-quota-params <integer> <fixedpoint> <fixedpoint> <fixedpoint>;
fetches-per-server <integer> [ ( drop | fail ) ];
fetches-per-zone <integer> [ ( drop | fail ) ];
flush-zones-on-shutdown <boolean>;
forward ( first | only );
forwarders [ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... };
fstrm-set-buffer-hint <integer>; // not configured
fstrm-set-flush-timeout <integer>; // not configured
fstrm-set-input-queue-size <integer>; // not configured
fstrm-set-output-notify-threshold <integer>; // not configured
fstrm-set-output-queue-model ( mpscs | spscs ); // not configured
fstrm-set-output-queue-size <integer>; // not configured
fstrm-set-reopen-interval <duration>; // not configured
geoip-directory ( <quoted_string> | none );
hostname ( <quoted_string> | none );
http-listener-clients <integer>;
http-port <integer>;
http-streams-per-connection <integer>;
https-port <integer>;
interface-interval <duration>;
ipv4only-contact <string>;
ipv4only-enable <boolean>;
ipv4only-server <string>;
ixfr-from-differences ( primary | master | secondary | slave | <boolean> );
key-directory <quoted_string>;
lame-ttl <duration>;
listen-on [ port <integer> ] [ proxy <string> ] [ tls <string> ] [ http <string> ] { <address_match_element>; ... }; // may occur multiple times
listen-on-v6 [ port <integer> ] [ proxy <string> ] [ tls <string> ] [ http <string> ] { <address_match_element>; ... }; // may occur multiple times
lmdb-mapsize <sizeval>;
managed-keys-directory <quoted_string>;
masterfile-format ( raw | text );
masterfile-style ( full | relative );
match-mapped-addresses <boolean>;
max-cache-size ( default | unlimited | <sizeval> | <percentage> );
max-cache-ttl <duration>;
max-clients-per-query <integer>;
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-ncache-ttl <duration>;
max-query-count <integer>;
max-query-restarts <integer>;
max-records <integer>;
max-records-per-type <integer>;
max-recursion-depth <integer>;
max-recursion-queries <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-rsa-exponent-size <integer>;
max-stale-ttl <duration>;
max-transfer-idle-in <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
max-types-per-name <integer>;
max-udp-size <integer>;
max-validation-failures-per-fetch <integer>; // experimental
max-validations-per-fetch <integer>; // experimental
memstatistics <boolean>;
memstatistics-file <quoted_string>;
message-compression <boolean>;
min-cache-ttl <duration>;
min-ncache-ttl <duration>;
min-refresh-time <integer>;
min-retry-time <integer>;
min-transfer-rate-in <integer> <integer>;
minimal-any <boolean>;
minimal-responses ( no-auth | no-auth-recursive | <boolean> );
multi-master <boolean>;
new-zones-directory <quoted_string>;
no-case-compress { <address_match_element>; ... };
nocookie-udp-size <integer>;
notify ( explicit | master-only | primary-only | <boolean> );
notify-defer <integer>;
notify-delay <integer>;
notify-rate <integer>;
notify-source ( <ipv4_address> | * ) ;
notify-source-v6 ( <ipv6_address> | * ) ;
notify-to-soa <boolean>;
nsec3-test-zone <boolean>; // test only
nta-lifetime <duration>;
nta-recheck <duration>;
nxdomain-redirect <string>;
parental-source ( <ipv4_address> | * ) ;
parental-source-v6 ( <ipv6_address> | * ) ;
pid-file ( <quoted_string> | none );
port <integer>;
preferred-glue <string>;
prefetch <integer> [ <integer> ];
provide-ixfr <boolean>;
qname-minimization ( strict | relaxed | disabled | off );
query-source [ address ] ( <ipv4_address> | * | none );
query-source-v6 [ address ] ( <ipv6_address> | * | none );
querylog <boolean>;
rate-limit {
all-per-second <integer>;
errors-per-second <integer>;
exempt-clients { <address_match_element>; ... };
ipv4-prefix-length <integer>;
ipv6-prefix-length <integer>;
log-only <boolean>;
max-table-size <integer>;
min-table-size <integer>;
nodata-per-second <integer>;
nxdomains-per-second <integer>;
qps-scale <integer>;
referrals-per-second <integer>;
responses-per-second <integer>;
slip <integer>;
window <integer>;
};
recursing-file <quoted_string>;
recursion <boolean>;
recursive-clients <integer>;
request-expire <boolean>;
request-ixfr <boolean>;
request-nsid <boolean>;
require-server-cookie <boolean>;
resolver-query-timeout <integer>;
resolver-use-dns64 <boolean>;
response-padding { <address_match_element>; ... } block-size <integer>;
response-policy { zone <string> [ add-soa <boolean> ] [ log <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only <quoted_string> ) ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ ede <string> ]; ... } [ add-soa <boolean> ] [ break-dnssec <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ min-ns-dots <integer> ] [ nsip-wait-recurse <boolean> ] [ nsdname-wait-recurse <boolean> ] [ qname-wait-recurse <boolean> ] [ recursive-only <boolean> ] [ servfail-until-ready <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ dnsrps-enable <boolean> ] [ dnsrps-options { <unspecified-text> } ];
responselog <boolean>;
reuseport <boolean>;
root-key-sentinel <boolean>;
rrset-order { [ class <string> ] [ type <string> ] [ name <quoted_string> ] <string> <string>; ... };
secroots-file <quoted_string>;
send-cookie <boolean>;
serial-query-rate <integer>;
serial-update-method ( date | increment | unixtime );
server-id ( <quoted_string> | none | hostname );
servfail-ttl <duration>;
session-keyalg <string>;
session-keyfile ( <quoted_string> | none );
session-keyname <string>;
sig-signing-nodes <integer>;
sig-signing-signatures <integer>;
sig-signing-type <integer>;
sig-validity-interval <integer> [ <integer> ]; // obsolete
sig0-checks-quota <integer>; // experimental
sig0-checks-quota-exempt { <address_match_element>; ... }; // experimental
sig0-key-checks-limit <integer>;
sig0-message-checks-limit <integer>;
sortlist { <address_match_element>; ... }; // deprecated
stale-answer-client-timeout ( disabled | off | <integer> );
stale-answer-enable <boolean>;
stale-answer-ttl <duration>;
stale-cache-enable <boolean>;
stale-refresh-time <duration>;
startup-notify-rate <integer>;
statistics-file <quoted_string>;
synth-from-dnssec <boolean>;
tcp-advertised-timeout <integer>;
tcp-clients <integer>;
tcp-idle-timeout <integer>;
tcp-initial-timeout <integer>;
tcp-keepalive-timeout <integer>;
tcp-listen-queue <integer>;
tcp-receive-buffer <integer>;
tcp-send-buffer <integer>;
tkey-domain <quoted_string>; // obsolete
tkey-gssapi-keytab <quoted_string>;
tls-port <integer>;
transfer-format ( many-answers | one-answer );
transfer-message-size <integer>;
transfer-source ( <ipv4_address> | * ) ;
transfer-source-v6 ( <ipv6_address> | * ) ;
transfers-in <integer>;
transfers-out <integer>;
transfers-per-ns <integer>;
trust-anchor-telemetry <boolean>;
try-tcp-refresh <boolean>;
udp-receive-buffer <integer>;
udp-send-buffer <integer>;
update-check-ksk <boolean>; // obsolete
update-quota <integer>;
use-v4-udp-ports { <portrange>; ... }; // deprecated
use-v6-udp-ports { <portrange>; ... }; // deprecated
v6-bias <integer>;
validate-except { <string>; ... };
version ( <quoted_string> | none );
zero-no-soa-ttl <boolean>;
zero-no-soa-ttl-cache <boolean>;
zone-statistics ( full | terse | none | <boolean> );
};
plugin ( query ) <string> [ { <unspecified-text> } ]; // may occur multiple times
remote-servers <string> [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... }; // may occur multiple times
server <netprefix> {
bogus <boolean>;
edns <boolean>;
edns-udp-size <integer>;
edns-version <integer>;
keys <server_key>;
max-udp-size <integer>;
notify-source ( <ipv4_address> | * ) ;
notify-source-v6 ( <ipv6_address> | * ) ;
padding <integer>;
provide-ixfr <boolean>;
query-source [ address ] ( <ipv4_address> | * );
query-source-v6 [ address ] ( <ipv6_address> | * );
request-expire <boolean>;
request-ixfr <boolean>;
request-nsid <boolean>;
require-cookie <boolean>;
send-cookie <boolean>;
tcp-keepalive <boolean>;
tcp-only <boolean>;
transfer-format ( many-answers | one-answer );
transfer-source ( <ipv4_address> | * ) ;
transfer-source-v6 ( <ipv6_address> | * ) ;
transfers <integer>;
}; // may occur multiple times
statistics-channels {
inet ( <ipv4_address> | <ipv6_address> | * ) [ port ( <integer> | * ) ] [ allow { <address_match_element>; ... } ]; // may occur multiple times
}; // may occur multiple times
tls <string> {
ca-file <quoted_string>;
cert-file <quoted_string>;
cipher-suites <string>;
ciphers <string>;
dhparam-file <quoted_string>;
key-file <quoted_string>;
prefer-server-ciphers <boolean>;
protocols { <string>; ... };
remote-hostname <quoted_string>;
session-tickets <boolean>;
}; // may occur multiple times
trust-anchors { <string> ( static-key | initial-key | static-ds | initial-ds ) <integer> <integer> <integer> <quoted_string>; ... }; // may occur multiple times
trusted-keys { <string> <integer> <integer> <integer> <quoted_string>; ... }; // may occur multiple times, deprecated
view <string> [ <class> ] {
allow-new-zones <boolean>;
allow-notify { <address_match_element>; ... };
allow-proxy { <address_match_element>; ... }; // experimental
allow-proxy-on { <address_match_element>; ... }; // experimental
allow-query { <address_match_element>; ... };
allow-query-cache { <address_match_element>; ... };
allow-query-cache-on { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
allow-recursion { <address_match_element>; ... };
allow-recursion-on { <address_match_element>; ... };
allow-transfer [ port <integer> ] [ transport <string> ] { <address_match_element>; ... };
allow-update { <address_match_element>; ... };
allow-update-forwarding { <address_match_element>; ... };
also-notify [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
attach-cache <string>;
auth-nxdomain <boolean>;
catalog-zones { zone <string> [ default-primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... } ] [ zone-directory <quoted_string> ] [ in-memory <boolean> ] [ min-update-interval <duration> ]; ... };
check-dup-records ( fail | warn | ignore );
check-integrity <boolean>;
check-mx ( fail | warn | ignore );
check-mx-cname ( fail | warn | ignore );
check-names ( primary | master | secondary | slave | response ) ( fail | warn | ignore ); // may occur multiple times
check-sibling <boolean>;
check-spf ( warn | ignore );
check-srv-cname ( fail | warn | ignore );
check-svcb <boolean>;
check-wildcard <boolean>;
clients-per-query <integer>;
deny-answer-addresses { <address_match_element>; ... } [ except-from { <string>; ... } ];
deny-answer-aliases { <string>; ... } [ except-from { <string>; ... } ];
dialup ( notify | notify-passive | passive | refresh | <boolean> ); // deprecated
disable-algorithms <string> { <string>; ... }; // may occur multiple times
disable-ds-digests <string> { <string>; ... }; // may occur multiple times
disable-empty-zone <string>; // may occur multiple times
dlz <string> {
database <string>;
search <boolean>;
}; // may occur multiple times
dns64 <netprefix> {
break-dnssec <boolean>;
clients { <address_match_element>; ... };
exclude { <address_match_element>; ... };
mapped { <address_match_element>; ... };
recursive-only <boolean>;
suffix <ipv6_address>;
}; // may occur multiple times
dns64-contact <string>;
dns64-server <string>;
dnskey-sig-validity <integer>; // obsolete
dnsrps-enable <boolean>; // not configured
dnsrps-options { <unspecified-text> }; // not configured
dnssec-accept-expired <boolean>;
dnssec-dnskey-kskonly <boolean>; // obsolete
dnssec-loadkeys-interval <integer>;
dnssec-must-be-secure <string> <boolean>; // may occur multiple times, deprecated
dnssec-policy <string>;
dnssec-secure-to-insecure <boolean>; // obsolete
dnssec-update-mode ( maintain | no-resign ) ; // obsolete
dnssec-validation ( yes | no | auto );
dnstap { ( all | auth | client | forwarder | resolver | update ) [ ( query | response ) ]; ... }; // not configured
dual-stack-servers [ port <integer> ] { ( <quoted_string> [ port <integer> ] | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ); ... };
dyndb <string> <quoted_string> { <unspecified-text> }; // may occur multiple times
edns-udp-size <integer>;
empty-contact <string>;
empty-server <string>;
empty-zones-enable <boolean>;
fetch-quota-params <integer> <fixedpoint> <fixedpoint> <fixedpoint>;
fetches-per-server <integer> [ ( drop | fail ) ];
fetches-per-zone <integer> [ ( drop | fail ) ];
forward ( first | only );
forwarders [ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... };
ipv4only-contact <string>;
ipv4only-enable <boolean>;
ipv4only-server <string>;
ixfr-from-differences ( primary | master | secondary | slave | <boolean> );
key <string> {
algorithm <string>;
secret <string>;
}; // may occur multiple times
key-directory <quoted_string>;
lame-ttl <duration>;
lmdb-mapsize <sizeval>;
masterfile-format ( raw | text );
masterfile-style ( full | relative );
match-clients { <address_match_element>; ... };
match-destinations { <address_match_element>; ... };
match-recursive-only <boolean>;
max-cache-size ( default | unlimited | <sizeval> | <percentage> );
max-cache-ttl <duration>;
max-clients-per-query <integer>;
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-ncache-ttl <duration>;
max-query-count <integer>;
max-query-restarts <integer>;
max-records <integer>;
max-records-per-type <integer>;
max-recursion-depth <integer>;
max-recursion-queries <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-stale-ttl <duration>;
max-transfer-idle-in <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
max-types-per-name <integer>;
max-udp-size <integer>;
max-validation-failures-per-fetch <integer>; // experimental
max-validations-per-fetch <integer>; // experimental
message-compression <boolean>;
min-cache-ttl <duration>;
min-ncache-ttl <duration>;
min-refresh-time <integer>;
min-retry-time <integer>;
min-transfer-rate-in <integer> <integer>;
minimal-any <boolean>;
minimal-responses ( no-auth | no-auth-recursive | <boolean> );
multi-master <boolean>;
new-zones-directory <quoted_string>;
no-case-compress { <address_match_element>; ... };
nocookie-udp-size <integer>;
notify ( explicit | master-only | primary-only | <boolean> );
notify-defer <integer>;
notify-delay <integer>;
notify-source ( <ipv4_address> | * ) ;
notify-source-v6 ( <ipv6_address> | * ) ;
notify-to-soa <boolean>;
nsec3-test-zone <boolean>; // test only
nta-lifetime <duration>;
nta-recheck <duration>;
nxdomain-redirect <string>;
parental-source ( <ipv4_address> | * ) ;
parental-source-v6 ( <ipv6_address> | * ) ;
plugin ( query ) <string> [ { <unspecified-text> } ]; // may occur multiple times
preferred-glue <string>;
prefetch <integer> [ <integer> ];
provide-ixfr <boolean>;
qname-minimization ( strict | relaxed | disabled | off );
query-source [ address ] ( <ipv4_address> | * | none );
query-source-v6 [ address ] ( <ipv6_address> | * | none );
rate-limit {
all-per-second <integer>;
errors-per-second <integer>;
exempt-clients { <address_match_element>; ... };
ipv4-prefix-length <integer>;
ipv6-prefix-length <integer>;
log-only <boolean>;
max-table-size <integer>;
min-table-size <integer>;
nodata-per-second <integer>;
nxdomains-per-second <integer>;
qps-scale <integer>;
referrals-per-second <integer>;
responses-per-second <integer>;
slip <integer>;
window <integer>;
};
recursion <boolean>;
request-expire <boolean>;
request-ixfr <boolean>;
request-nsid <boolean>;
require-server-cookie <boolean>;
resolver-query-timeout <integer>;
resolver-use-dns64 <boolean>;
response-padding { <address_match_element>; ... } block-size <integer>;
response-policy { zone <string> [ add-soa <boolean> ] [ log <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only <quoted_string> ) ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ ede <string> ]; ... } [ add-soa <boolean> ] [ break-dnssec <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ min-ns-dots <integer> ] [ nsip-wait-recurse <boolean> ] [ nsdname-wait-recurse <boolean> ] [ qname-wait-recurse <boolean> ] [ recursive-only <boolean> ] [ servfail-until-ready <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ dnsrps-enable <boolean> ] [ dnsrps-options { <unspecified-text> } ];
root-key-sentinel <boolean>;
rrset-order { [ class <string> ] [ type <string> ] [ name <quoted_string> ] <string> <string>; ... };
send-cookie <boolean>;
serial-update-method ( date | increment | unixtime );
server <netprefix> {
bogus <boolean>;
edns <boolean>;
edns-udp-size <integer>;
edns-version <integer>;
keys <server_key>;
max-udp-size <integer>;
notify-source ( <ipv4_address> | * ) ;
notify-source-v6 ( <ipv6_address> | * ) ;
padding <integer>;
provide-ixfr <boolean>;
query-source [ address ] ( <ipv4_address> | * );
query-source-v6 [ address ] ( <ipv6_address> | * );
request-expire <boolean>;
request-ixfr <boolean>;
request-nsid <boolean>;
require-cookie <boolean>;
send-cookie <boolean>;
tcp-keepalive <boolean>;
tcp-only <boolean>;
transfer-format ( many-answers | one-answer );
transfer-source ( <ipv4_address> | * ) ;
transfer-source-v6 ( <ipv6_address> | * ) ;
transfers <integer>;
}; // may occur multiple times
servfail-ttl <duration>;
sig-signing-nodes <integer>;
sig-signing-signatures <integer>;
sig-signing-type <integer>;
sig-validity-interval <integer> [ <integer> ]; // obsolete
sig0-key-checks-limit <integer>;
sig0-message-checks-limit <integer>;
sortlist { <address_match_element>; ... }; // deprecated
stale-answer-client-timeout ( disabled | off | <integer> );
stale-answer-enable <boolean>;
stale-answer-ttl <duration>;
stale-cache-enable <boolean>;
stale-refresh-time <duration>;
synth-from-dnssec <boolean>;
transfer-format ( many-answers | one-answer );
transfer-source ( <ipv4_address> | * ) ;
transfer-source-v6 ( <ipv6_address> | * ) ;
trust-anchor-telemetry <boolean>;
trust-anchors { <string> ( static-key | initial-key | static-ds | initial-ds ) <integer> <integer> <integer> <quoted_string>; ... }; // may occur multiple times
trusted-keys { <string> <integer> <integer> <integer> <quoted_string>; ... }; // may occur multiple times, deprecated
try-tcp-refresh <boolean>;
v6-bias <integer>;
validate-except { <string>; ... };
zero-no-soa-ttl <boolean>;
zero-no-soa-ttl-cache <boolean>;
zone-statistics ( full | terse | none | <boolean> );
}; // may occur multiple times

View File

@@ -0,0 +1,63 @@
zone <string> [ <class> ] {
type primary;
allow-query { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
allow-transfer [ port <integer> ] [ transport <string> ] { <address_match_element>; ... };
allow-update { <address_match_element>; ... };
also-notify [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
check-dup-records ( fail | warn | ignore );
check-integrity <boolean>;
check-mx ( fail | warn | ignore );
check-mx-cname ( fail | warn | ignore );
check-names ( fail | warn | ignore );
check-sibling <boolean>;
check-spf ( warn | ignore );
check-srv-cname ( fail | warn | ignore );
check-svcb <boolean>;
check-wildcard <boolean>;
checkds ( explicit | <boolean> );
database <string>;
dialup ( notify | notify-passive | passive | refresh | <boolean> ); // deprecated
dlz <string>;
dnskey-sig-validity <integer>; // obsolete
dnssec-dnskey-kskonly <boolean>; // obsolete
dnssec-loadkeys-interval <integer>;
dnssec-policy <string>;
dnssec-secure-to-insecure <boolean>; // obsolete
dnssec-update-mode ( maintain | no-resign ) ; // obsolete
file <quoted_string>;
forward ( first | only );
forwarders [ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... };
inline-signing <boolean>;
ixfr-from-differences <boolean>;
journal <quoted_string>;
key-directory <quoted_string>;
masterfile-format ( raw | text );
masterfile-style ( full | relative );
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
max-records-per-type <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-out <integer>;
max-types-per-name <integer>;
max-zone-ttl ( unlimited | <duration> ); // deprecated
notify ( explicit | master-only | primary-only | <boolean> );
notify-defer <integer>;
notify-delay <integer>;
notify-source ( <ipv4_address> | * ) ;
notify-source-v6 ( <ipv6_address> | * ) ;
notify-to-soa <boolean>;
nsec3-test-zone <boolean>; // test only
parental-agents [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
parental-source ( <ipv4_address> | * ) ;
parental-source-v6 ( <ipv6_address> | * ) ;
serial-update-method ( date | increment | unixtime );
sig-signing-nodes <integer>;
sig-signing-signatures <integer>;
sig-signing-type <integer>;
sig-validity-interval <integer> [ <integer> ]; // obsolete
update-policy ( local | { ( deny | grant ) <string> ( 6to4-self | external | krb5-self | krb5-selfsub | krb5-subdomain | krb5-subdomain-self-rhs | ms-self | ms-selfsub | ms-subdomain | ms-subdomain-self-rhs | name | self | selfsub | selfwild | subdomain | tcp-self | wildcard | zonesub ) [ <string> ] <rrtype list>; ... } );
zero-no-soa-ttl <boolean>;
zone-statistics ( full | terse | none | <boolean> );
};

View File

@@ -0,0 +1,15 @@
zone <string> [ <class> ] {
type redirect;
allow-query { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
dlz <string>;
file <quoted_string>;
masterfile-format ( raw | text );
masterfile-style ( full | relative );
max-records <integer>;
max-records-per-type <integer>;
max-types-per-name <integer>;
max-zone-ttl ( unlimited | <duration> ); // deprecated
primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
zone-statistics ( full | terse | none | <boolean> );
};

View File

@@ -0,0 +1,20 @@
key <string> {
algorithm <string>;
secret <string>;
}; // may occur multiple times
options {
default-key <string>;
default-port <integer>;
default-server <string>;
default-source-address ( <ipv4_address> | * );
default-source-address-v6 ( <ipv6_address> | * );
};
server <string> {
addresses { ( <quoted_string> [ port <integer> ] | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ); ... };
key <string>;
port <integer>;
source-address ( <ipv4_address> | * );
source-address-v6 ( <ipv6_address> | * );
}; // may occur multiple times

View File

@@ -0,0 +1,66 @@
zone <string> [ <class> ] {
type secondary;
allow-notify { <address_match_element>; ... };
allow-query { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
allow-transfer [ port <integer> ] [ transport <string> ] { <address_match_element>; ... };
allow-update-forwarding { <address_match_element>; ... };
also-notify [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
check-names ( fail | warn | ignore );
checkds ( explicit | <boolean> );
database <string>;
dialup ( notify | notify-passive | passive | refresh | <boolean> ); // deprecated
dlz <string>;
dnskey-sig-validity <integer>; // obsolete
dnssec-dnskey-kskonly <boolean>; // obsolete
dnssec-loadkeys-interval <integer>;
dnssec-policy <string>;
dnssec-update-mode ( maintain | no-resign ) ; // obsolete
file <quoted_string>;
forward ( first | only );
forwarders [ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... };
inline-signing <boolean>;
ixfr-from-differences <boolean>;
journal <quoted_string>;
key-directory <quoted_string>;
masterfile-format ( raw | text );
masterfile-style ( full | relative );
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
max-records-per-type <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
max-types-per-name <integer>;
min-refresh-time <integer>;
min-retry-time <integer>;
min-transfer-rate-in <integer> <integer>;
multi-master <boolean>;
notify ( explicit | master-only | primary-only | <boolean> );
notify-defer <integer>;
notify-delay <integer>;
notify-source ( <ipv4_address> | * ) ;
notify-source-v6 ( <ipv6_address> | * ) ;
notify-to-soa <boolean>;
nsec3-test-zone <boolean>; // test only
parental-agents [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
parental-source ( <ipv4_address> | * ) ;
parental-source-v6 ( <ipv6_address> | * ) ;
primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
request-expire <boolean>;
request-ixfr <boolean>;
sig-signing-nodes <integer>;
sig-signing-signatures <integer>;
sig-signing-type <integer>;
sig-validity-interval <integer> [ <integer> ]; // obsolete
transfer-source ( <ipv4_address> | * ) ;
transfer-source-v6 ( <ipv6_address> | * ) ;
try-tcp-refresh <boolean>;
update-check-ksk <boolean>; // obsolete
zero-no-soa-ttl <boolean>;
zone-statistics ( full | terse | none | <boolean> );
};

View File

@@ -0,0 +1,13 @@
zone <string> [ <class> ] {
type static-stub;
allow-query { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
forward ( first | only );
forwarders [ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... };
max-records <integer>;
max-records-per-type <integer>;
max-types-per-name <integer>;
server-addresses { ( <ipv4_address> | <ipv6_address> ); ... };
server-names { <string>; ... };
zone-statistics ( full | terse | none | <boolean> );
};

View File

@@ -0,0 +1,28 @@
zone <string> [ <class> ] {
type stub;
allow-query { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
check-names ( fail | warn | ignore );
database <string>;
dialup ( notify | notify-passive | passive | refresh | <boolean> ); // deprecated
file <quoted_string>;
forward ( first | only );
forwarders [ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... };
masterfile-format ( raw | text );
masterfile-style ( full | relative );
max-records <integer>;
max-records-per-type <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
max-transfer-time-in <integer>;
max-types-per-name <integer>;
min-refresh-time <integer>;
min-retry-time <integer>;
min-transfer-rate-in <integer> <integer>;
multi-master <boolean>;
primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
transfer-source ( <ipv4_address> | * ) ;
transfer-source-v6 ( <ipv6_address> | * ) ;
zone-statistics ( full | terse | none | <boolean> );
};

View File

@@ -0,0 +1,85 @@
{
"zone": {
"_id": "<string> [ <class> ]",
"_mapbody": {
"type": {
"_grammar": "stub"
},
"allow-query": {
"_grammar": "{ <address_match_element>; ... }"
},
"allow-query-on": {
"_grammar": "{ <address_match_element>; ... }"
},
"check-names": {
"_grammar": "( fail | warn | ignore )"
},
"database": {
"_grammar": "<string>"
},
"file": {
"_grammar": "<quoted_string>"
},
"forward": {
"_grammar": "( first | only )"
},
"forwarders": {
"_grammar": "[ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... }"
},
"masterfile-format": {
"_grammar": "( raw | text )"
},
"masterfile-style": {
"_grammar": "( full | relative )"
},
"max-records": {
"_grammar": "<integer>"
},
"max-records-per-type": {
"_grammar": "<integer>"
},
"max-refresh-time": {
"_grammar": "<integer>"
},
"max-retry-time": {
"_grammar": "<integer>"
},
"max-transfer-idle-in": {
"_grammar": "<integer>"
},
"max-transfer-time-in": {
"_grammar": "<integer>"
},
"max-types-per-name": {
"_grammar": "<integer>"
},
"min-refresh-time": {
"_grammar": "<integer>"
},
"min-retry-time": {
"_grammar": "<integer>"
},
"min-transfer-rate-in": {
"_grammar": "<integer> <integer>"
},
"multi-master": {
"_grammar": "<boolean>"
},
"primaries": {
"_grammar": "[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... }"
},
"template": {
"_grammar": "<string>"
},
"transfer-source": {
"_grammar": "( <ipv4_address> | * )"
},
"transfer-source-v6": {
"_grammar": "( <ipv6_address> | * )"
},
"zone-statistics": {
"_grammar": "( full | terse | none | <boolean> )"
}
}
}
}

View File

@@ -16,7 +16,6 @@ bind9_config_indent: 4
bind9_group_config: [] bind9_group_config: []
bind9_site_config: [] bind9_site_config: []
bind9_host_config: [] bind9_host_config: []
bind9_default_config: bind9_default_config:
- name: named.conf - name: named.conf
backup: false backup: false
@@ -28,10 +27,11 @@ bind9_default_config:
options: options:
directory: "{{ bind9_working_directory }}" directory: "{{ bind9_working_directory }}"
bind9_config: "{{ [bind9_default_config, bind9_config: >-
{{
[bind9_default_config,
bind9_group_config, bind9_group_config,
bind9_site_config, bind9_site_config,
bind9_host_config] | bind9_host_config] |
community.general.lists_mergeby('name', community.general.lists_mergeby('name', recursive=true, list_merge='append_rp')
recursive=true, }}
list_merge='append_rp') }}"

231
docs/BIND9_9.20_SUPPORT.md Normal file
View File

@@ -0,0 +1,231 @@
# BIND9 9.20 Support Implementation Guide
## Overview
This document describes the ansible-bind9-role implementation for BIND9 9.20+ support through the `feature/bind9-20-support` branch.
## Architecture
### Multi-Version Support Strategy
The role supports multiple BIND9 versions using:
1. **Runtime Version Detection**: BIND9 version is detected at runtime and stored in the `bind9_version` fact
2. **Template Conditionals**: Jinja2 conditionals in templates apply version-specific configurations
3. **Separate Branches**: Different BIND9 feature release series are maintained on separate branches
- `main`: BIND9 9.18.x (LTS) - Production stable
- `9.20`: BIND9 9.20+ (feature releases) - New features and modern approach
### Branch Structure
```
main # BIND9 9.18.x LTS (stable)
└─ 9.20 # BIND9 9.20+ feature releases
├─ feature/bind9-20-support # Current development branch
└─ (will merge to 9.20 after testing)
```
## Implementation Details
### 1. Version Detection (tasks/main.yml)
```yaml
- name: Detect BIND9 version at runtime
ansible.builtin.command:
cmd: named -v
register: _bind9_version_output
changed_when: false
- name: Set bind9_version fact
ansible.builtin.set_fact:
bind9_version: "{{ _bind9_version_output.stdout | regex_search('BIND (\\S+)', '\\1') | first }}"
```
### 2. Meta/Argument Specs Updates
The `meta/argument_specs.yml` has been updated to:
- Document BIND9 9.20+ support alongside 9.18.x
- Add `bind9_version` variable documentation (read-only, auto-detected)
- Clarify version-specific behavior
### 3. Molecule Testing
Two molecule scenarios are now available:
#### Default Scenario (BIND9 9.18.x)
- **Location**: `molecule/default/`
- **Platform**: Debian 13 (Trixie) with BIND9 9.18.x
- **Purpose**: Validate production-stable configurations
#### BIND9 9.20 Scenario
- **Location**: `molecule/bind9-20/`
- **Platform**: Ubuntu 24.04 LTS with BIND9 9.20+
- **Purpose**: Validate newer configurations and breaking changes
- **Tests**: Forward zones, TLS, DNSTAP, modern DNSSEC
### 4. Template Version Compatibility
Templates have been audited for BIND9 9.20 compatibility. The primary template files include:
- `named.conf.options.j2` - Global options block
- `named.conf.zone.j2` - Zone definitions
- `named.conf.primaries.j2` - Primary/secondary definitions
- `named.conf.tls.j2` - TLS configurations (9.20 focus)
- `named.conf.dnssec-policy.j2` - DNSSEC policies
### 5. Deprecated Options Handling
BIND9 9.20 removes 44 options from 9.18. The role handles this through:
1. **Documentation**: Each deprecated option is documented in BIND9_MIGRATION_GUIDE.md
2. **Conditional Removal**: Templates check version and exclude removed options
3. **Migration Path**: BIND9_MIGRATION_GUIDE.md provides alternatives for each removed option
## Critical BIND9 9.20 Changes
### Automatically Enabled Options
These cannot and should not be configured (always enabled in 9.20):
- `glue-cache` - Glue records are always cached
- `keep-response-order` - Response ordering is always enabled
- `reuse` - TCP socket reuse is always enabled
### Removed Global Options
Key removed options requiring configuration changes:
| 9.18 Option | 9.20 Replacement |
|---|---|
| `alt-transfer-source` | Use TLS in `primaries` statement |
| `alt-transfer-source-v6` | Use TLS in `primaries` statement |
| `auto-dnssec` | Automatic (DNSSEC always managed) |
| `dsc` | Use TLS configuration instead |
| `gssapi-credential` | Use TSIG + TLS instead |
| `heartbeat-interval` | Zone transfer monitoring improved |
| `lock-file` | OS-level locking used |
| `max-zone-ttl` | Use per-zone option instead |
| `parental-agents` | Use enhanced `primaries` statement |
| `parental-registration-delay` | Zone monitoring improved |
| `root-delegation-only` | Zone constraints |
| `suppress-initial-notify` | NOTIFY behavior changed |
| `tkeydhkey` | Use modern TLS/DNSSEC |
| `tkeygsapi-credential` | Use TSIG + TLS |
### New 9.20 Features
- **Native TLS/DoT Support**: Zone transfers over TLS
- **Automatic DNSSEC Management**: DNSSEC is handled automatically
- **Enhanced HTTP/HTTPS Server**: Built-in HTTP API
- **Better Resolver Behavior**: Improved retry and fallback logic
- **Query Monitoring**: Advanced query tracking and statistics
## Configuration Changes for 9.20
### Before (BIND9 9.18.x)
```yaml
bind9_default_config:
- name: named.conf.options
options:
alt_transfer_source: 10.0.1.1
glue_cache: yes
parental_agents:
- 192.0.2.1
- 192.0.2.2
```
### After (BIND9 9.20+)
```yaml
bind9_default_config:
- name: named.conf.options
options:
# Removed: alt_transfer_source, glue_cache, parental_agents
# Instead use TLS and enhanced primaries statement
- name: named.conf.zone
zones:
- name: example.com
type: secondary
primaries:
- address: 192.0.2.1
tls: zone-transfer-tls # New 9.20 approach
- address: 192.0.2.2
tls: zone-transfer-tls
```
## Testing the Implementation
### Running Molecule Tests
```bash
# Test both scenarios
molecule test
# Test only 9.18 scenario
molecule test -s default
# Test only 9.20 scenario
molecule test -s bind9-20
# Interactive testing
molecule create -s bind9-20
molecule converge -s bind9-20
molecule verify -s bind9-20
```
### Manual Validation
```bash
# Check BIND9 version
named -v
# Validate configuration syntax
named-checkconf /etc/bind/named.conf
# Check logs for version-related messages
journalctl -u named -n 50 -e
tail -f /var/log/named/default.log
```
## Migration Path
Users upgrading from 9.18 to 9.20 should:
1. **Review Configuration**: Check `BIND9_MIGRATION_GUIDE.md` for breaking changes
2. **Update Playbooks**: Remove deprecated variables/options
3. **Test in Staging**: Use `molecule test -s bind9-20` to validate
4. **Gradual Migration**: Test on non-critical servers first
5. **Monitor Logs**: Watch for deprecation or error messages
## Future Enhancements
- [ ] Automated configuration migration tool
- [ ] Deprecation warnings in role output
- [ ] 9.21+ preparation when available
- [ ] Performance tuning for 9.20 features
- [ ] DNS-over-HTTPS (DoH) support
- [ ] Clustering/high-availability examples
## References
- [ISC BIND9 Website](https://www.isc.org/bind/)
- [BIND9 9.20 Release Notes](https://www.isc.org/download/news/)
- [BIND9 Documentation](https://bind9.readthedocs.io/)
- [BIND9 Version Differences](../../docs/BIND_VERSION_DIFFERENCES.md)
- [BIND9 Migration Guide](../../docs/BIND9_MIGRATION_GUIDE.md)
- [VERSION_SUPPORT.md](../../docs/VERSION_SUPPORT.md)
## Support
For issues or questions about BIND9 9.20 support:
1. Check existing [Issues](https://git.valid.dk/daniel/ansible-bind9-role/issues)
2. Review [Discussions](https://git.valid.dk/daniel/ansible-bind9-role/discussions)
3. Create a new issue with:
- BIND9 version (`named -v`)
- Playbook configuration
- Error messages from logs
- Steps to reproduce

View File

@@ -0,0 +1,479 @@
# BIND9 9.18 to 9.20 Migration Guide
## Overview
This guide provides step-by-step instructions for migrating BIND9 configurations from version 9.18.x (LTS) to version 9.20.x.
**Important:** BIND9 9.20 introduces 44 breaking changes. Before upgrading, carefully review this guide and test in a development environment.
For detailed technical differences between versions, see [BIND9 Version Differences](BIND_VERSION_DIFFERENCES.md).
## Table of Contents
1. [Pre-Migration Planning](#pre-migration-planning)
2. [Breaking Changes Summary](#breaking-changes-summary)
3. [Migration Steps](#migration-steps)
4. [Configuration Examples](#configuration-examples)
5. [Role-Specific Changes](#role-specific-changes)
6. [Testing Recommendations](#testing-recommendations)
7. [Rollback Procedure](#rollback-procedure)
## Pre-Migration Planning
### Check Your Configuration
Before upgrading, identify which BIND9 options your configuration uses:
```bash
# Check for options that will be removed
named-checkconf -p /etc/bind/named.conf | \
grep -E "alt-transfer-source|auto-dnssec|coresize|datasize|glue-cache"
```
### Create Backups
```bash
# Backup all BIND configuration
cp -r /etc/bind /data/backup/bind.9.18.backup
# Backup BIND data
cp -r /var/lib/bind /data/backup/bind.9.18.data
cp -r /var/cache/bind /data/backup/bind.9.18.cache
```
### Review Version Support
This Ansible role is designed for BIND9 9.18.x. When upgrading to 9.20:
- The main branch will continue supporting 9.18.x
- A separate `9.20` branch will provide 9.20-specific templates and configurations
- Use the appropriate branch for your target BIND9 version
## Breaking Changes Summary
The following options are **removed** in BIND9 9.20 and will cause `named` to fail if present:
### Global Options (9.20 Breaking Changes)
- `alt-transfer-source` - Use TLS-based transfers instead
- `alt-transfer-source-v6` - Use TLS-based transfers instead
- `auto-dnssec` - DNSSEC management is automatic in 9.20
- `coresize` - System resource limits; use OS-level controls
- `datasize` - System resource limits; use OS-level controls
- `dscp` - Use TLS configuration instead
- `files` - System resource limits; use OS-level controls
- `glue-cache` - Always enabled in 9.20
- `heartbeat-interval` - Zone transfer changes
- `keep-response-order` - Always enabled in 9.20
- `lock-file` - Use system lock controls
- `maxz-zone-ttl` - Use `max-zone-ttl` instead (per-zone option)
- `parent-registration-delay` - Zone-delegation monitoring removed
- `parental-agents` - Use `primaries` statement with DNSSEC
- `primaries` - Replaced with enhanced syntax (see below)
- `random-device` - System entropy handling improved
- `recurse-ing-file` - Renamed to `recursing-file`
- `reserved-sockets` - Automatic in 9.20
- `resolver-nonbackoff-tries` - Resolver behavior changed
- `resolver-retry-interval` - Resolver behavior changed
- `reuse` - Always enabled in 9.20
- `root-delegation-only` - Removed; not needed in 9.20
- `stacksize` - System resource limits; use OS-level controls
- `suppress-initial-notify` - NOTIFY behavior changed
- `tkey-dhkey` - Use modern TLS/DNSSEC instead
- `tkey-gssapi-credential` - Use TSIG + TLS instead
### Zone-Type Specific Breaking Changes
#### All Zone Types
- `delegation-only` - Removed; use zone type constraints instead
- `alt-transfer-source[v6]` - Use TLS configuration
- `auto-dnssec` - DNSSEC management changes
- `use-alt-transfer-source` - Use TLS configuration
## Migration Steps
### Step 1: Identify Configuration Changes
Review your current `bind9_*_config` variables for any deprecated options:
```yaml
# Search your inventory and host_vars for these patterns
bind9_default_config:
- name: named.conf.options
options:
# These options must be removed or replaced:
# - alt_transfer_source
# - auto_dnssec
# - glue_cache
# ... etc
```
### Step 2: Update Ansible Variables
Replace deprecated options in your Ansible configuration:
```yaml
# BEFORE (BIND9 9.18)
bind9_default_config:
- name: named.conf.options
options:
alt_transfer_source: 10.0.1.1
glue_cache: yes
keep_response_order: yes
# AFTER (BIND9 9.20)
bind9_default_config:
- name: named.conf.options
options:
# alt_transfer_source removed - use TLS
# glue_cache removed - always enabled
# keep_response_order removed - always enabled
# Instead configure TLS for transfers
http:
preference: https
```
### Step 3: Update Primaries Configuration
The `primaries` statement syntax has changed:
```yaml
# BEFORE (BIND9 9.18)
bind9_host_config:
- name: named.conf.view
view:
- name: internal
zone:
- name: example.com
type: secondary
primaries:
- 192.0.2.1
- 192.0.2.2
# AFTER (BIND9 9.20)
bind9_host_config:
- name: named.conf.view
view:
- name: internal
zone:
- name: example.com
type: secondary
primaries:
- address: 192.0.2.1
- address: 192.0.2.2
# Optional: TLS configuration
# tls: cert-name
# source: 10.0.1.1
# source_v6: "2001:db8::1"
```
### Step 4: Validate Configuration
Before deploying to production:
```bash
# Validate syntax
named-checkconf /etc/bind/named.conf
# Check for deprecated options
grep -r "alt-transfer-source\|auto-dnssec\|glue-cache" /etc/bind/
```
### Step 5: Test Zone Operations
```bash
# Test zone transfers
dig @ns1.example.com example.com AXFR
# Test DNSSEC validation
dig @ns1.example.com example.com +dnssec
# Check BIND logs
journalctl -u bind9 -f
```
## Configuration Examples
### Example 1: Simple Secondary Zone Migration
**BIND9 9.18 Configuration:**
```yaml
bind9_default_config:
- name: named.conf.view
view:
- name: "default"
recursion: yes
zone:
- name: "example.com"
type: "secondary"
file: "/var/lib/bind/example.com.zone"
primaries:
- 192.0.2.1
- 192.0.2.2
alt_transfer_source: 10.0.1.1
alt_transfer_source_v6: "2001:db8::1"
allow_transfer:
- 10.0.2.0/24
```
**BIND9 9.20 Configuration:**
```yaml
bind9_default_config:
- name: named.conf.view
view:
- name: "default"
recursion: yes
zone:
- name: "example.com"
type: "secondary"
file: "/var/lib/bind/example.com.zone"
primaries:
- address: 192.0.2.1
- address: 192.0.2.2
# alt_transfer_source removed - use TLS
# Configuration now uses single source per address:
allow_transfer:
- 10.0.2.0/24
```
### Example 2: DNSSEC Configuration Migration
**BIND9 9.18 Configuration:**
```yaml
bind9_default_config:
- name: named.conf.options
options:
dnssec_policy: default
- name: named.conf.zone
zone:
- name: "example.com"
type: "primary"
file: "/var/lib/bind/example.com.zone"
auto_dnssec: maintain
inline_signing: yes
```
**BIND9 9.20 Configuration:**
```yaml
bind9_default_config:
- name: named.conf.options
options:
dnssec_policy: default
- name: named.conf.zone
zone:
- name: "example.com"
type: "primary"
file: "/var/lib/bind/example.com.zone"
# auto_dnssec removed - DNSSEC management is automatic
dnssec_policy: default # Explicitly set policy
inline_signing: yes # Still supported
```
## Role-Specific Changes
### Branch Selection
When using this Ansible role with BIND9 9.20, you have two options:
#### Option 1: Use Main Branch (Recommended for 9.18)
```bash
# Use main branch for BIND9 9.18
ansible-galaxy install daniel.ansible-bind9-role
```
#### Option 2: Use 9.20 Branch (When Available)
```bash
# Clone the 9.20 branch for BIND9 9.20 support
git clone --branch 9.20 https://git.valid.dk/daniel/ansible-bind9-role.git
```
### Template Variables
No Ansible variable names change between versions. However, the **values** for some variables may need adjustment:
```yaml
# Variable names stay the same (kebab-case → snake_case)
# Example: "alt-transfer-source" → "alt_transfer_source"
# Simply remove deprecated variables - they will be ignored
bind9_default_config:
- name: named.conf.options
options:
# Remove these:
# alt_transfer_source: ...
# auto_dnssec: ...
# glue_cache: ...
# These still work:
dnssec_validation: yes
recursion: yes
allow_query:
- any
```
### DNSSEC Policy Changes
BIND9 9.20 improves DNSSEC handling:
```yaml
# Both versions support dnssec_policy
bind9_default_config:
- name: named.conf.dnssec-policy
dnssec_policy:
- name: default
keys:
- lifetime: 3600
algorithm: ecdsap256sha256
role:
- ksk
- zsk
nsec3param:
iterations: 0
optout: no
salt_length: 32
```
## Testing Recommendations
### Test Environment Setup
Create a test playbook to validate migration:
```yaml
---
- hosts: test_servers
vars:
bind9_version: "9.20" # Document version being tested
tasks:
- name: Apply BIND9 9.20 configuration
include_role:
name: ansible-bind9-role
- name: Validate configuration
command: named-checkconf /etc/bind/named.conf
register: config_check
failed_when: config_check.rc != 0
- name: Test zone transfers
command: >
dig @localhost example.com AXFR
register: zone_transfer
- name: Test DNSSEC validation
command: >
dig @localhost example.com +dnssec
register: dnssec_test
- name: Check BIND status
systemd:
name: bind9
state: started
register: bind_status
```
### Validation Checklist
- [ ] Configuration syntax valid (`named-checkconf`)
- [ ] BIND9 service starts without errors
- [ ] All zones load successfully
- [ ] Zone transfers complete successfully
- [ ] Queries resolve correctly
- [ ] DNSSEC validation works
- [ ] Secondary zones receive updates
- [ ] No errors in BIND logs
- [ ] Performance is acceptable
## Rollback Procedure
If issues occur after migration:
### Immediate Rollback
```bash
# Stop BIND9
systemctl stop bind9
# Restore configuration backup
rm -rf /etc/bind
cp -r /data/backup/bind.9.18.backup /etc/bind
# Restore zone files
rm -rf /var/lib/bind
cp -r /data/backup/bind.9.18.data /var/lib/bind
cp -r /data/backup/bind.9.18.cache /var/cache/bind
# Restore BIND9 package
apt-get install --reinstall bind9=1:9.18.44-1+0~20240101.3+debian~bullseye+1+sury+1
# Start BIND9
systemctl start bind9
# Verify
systemctl status bind9
dig @localhost example.com
```
### Using Ansible Rollback
```yaml
---
- hosts: bind_servers
tasks:
- name: Restore BIND9 9.18 package
apt:
name: bind9=1:9.18.44-1+0~20240101.3+debian~bullseye+1+sury+1
state: present
- name: Restore configuration from backup
synchronize:
src: /data/backup/bind.9.18.backup/
dest: /etc/bind/
delete: yes
mode: push
- name: Restart BIND9
systemd:
name: bind9
state: restarted
daemon_reload: yes
```
## Additional Resources
- [BIND9 Version Differences](BIND_VERSION_DIFFERENCES.md) - Technical comparison
- [ISC BIND9 Release Notes](https://www.isc.org/bind/) - Official documentation
- [BIND9 9.20 Features](https://bind.readthedocs.io/en/latest/) - Feature details
- [Role Configuration Reference](CONFIGURATION_GRAMMAR.md) - Ansible role documentation
## Getting Help
For issues during migration:
1. Check [BIND9 Version Differences](BIND_VERSION_DIFFERENCES.md) for specific option changes
2. Review BIND9 logs: `journalctl -u bind9 -n 100`
3. Validate configuration: `named-checkconf /etc/bind/named.conf`
4. Test in development environment first
5. Document any custom options that need special handling
## Version Support Timeline
- **BIND9 9.18.x (LTS)**: Supported until September 2026
- This Ansible role's current focus
- Main branch targets 9.18.x configurations
- **BIND9 9.20.x**: Available now
- Future branch (`9.20`) being prepared
- Plan migration during non-critical periods
- **BIND9 9.22.x**: Coming in 2026
- Further breaking changes expected
- Will require additional migration steps
Plan upgrades within your maintenance windows and test thoroughly before production deployment.

View File

@@ -0,0 +1,552 @@
# BIND9 Version Differences: v9.18.44 vs v9.20.18
This document compares BIND9 configuration grammar between v9.18.44 and v9.20.18.
Generated automatically by `scripts/compare_bind_versions.py`.
## Summary
- **New Options**: 35
- **Removed Options**: 44 ⚠️
- **Modified Options**: 22
- **Newly Deprecated**: 3
## ⚠️ Breaking Changes
The following options were removed in v9.20.18 and will cause configuration errors:
### options
- `alt-transfer-source`
- `alt-transfer-source-v6`
- `auto-dnssec`
- `coresize`
- `datasize`
- `dscp`
- `files`
- `glue-cache`
- `heartbeat-interval`
- `keep-response-order`
- `lock-file`
- `maxz-zone-ttl`
- `parent-registration-delay`
- `parental-agents`
- `primaries`
- `random-device`
- `recurse-ing-file`
- `reserved-sockets`
- `resolver-nonbackoff-tries`
- `resolver-retry-interval`
- `reuse`
- `root-delegation-only`
- `stacksize`
- `suppress-initial-notify`
- `tkey-dhkey`
- `tkey-gssapi-credential`
- `use-alt-transfer-source`
### forward.zoneopt
- `delegation-only`
### hint.zoneopt
- `delegation-only`
### mirror.zoneopt
- `alt-transfer-source`
- `alt-transfer-source-v6`
- `use-alt-transfer-source`
### primary.zoneopt
- `alt-transfer-source`
- `alt-transfer-source-v6`
- `auto-dnssec`
- `update-check-ksk`
### secondary.zoneopt
- `alt-transfer-source`
- `alt-transfer-source-v6`
- `auto-dnssec`
- `use-alt-transfer-source`
### stub.zoneopt
- `delegation-only`
- `use-alt-transfer-source`
### delegation-only.zoneopt
- `type`
- `zone`
## ✨ New Features
The following options were added in v9.20.18:
### options
- `allow-proxy`
- `allow-proxy-on`
- `cdnskey`
- `cds-digest-types`
- `check-svcb`
- `cipher-suites`
- `dnsrps-library`
- `inline-signing`
- `key-store`
- `manual-mode`
- `max-validation-failures-per-fetch`
- `max-validations-per-fetch`
- `min-transfer-rate-in`
- `notify-defer`
- `offline-ksk`
- `pkcs11-uri`
- `recursing-file`
- `remote-servers`
- `require-cookie`
- `resolver-use-dns64`
- `responselog`
- `reuseport`
- `sig0-checks-quota`
- `sig0-checks-quota-exempt`
- `sig0-key-checks-limit`
- `sig0-message-checks-limit`
### mirror.zoneopt
- `min-transfer-rate-in`
- `notify-defer`
### primary.zoneopt
- `check-svcb`
- `checkds`
- `notify-defer`
### secondary.zoneopt
- `checkds`
- `min-transfer-rate-in`
- `notify-defer`
### stub.zoneopt
- `min-transfer-rate-in`
## 🔧 Modified Options
The following options have syntax changes in v9.20.18:
### options
#### `listen-on`
**v9.18.44**:
```
[ port <integer> ] [ tls <string> ] [ http <string> ] { <address_match_element>
```
**v9.20.18**:
```
[ port <integer> ] [ proxy <string> ] [ tls <string> ] [ http <string> ] { <address_match_element>
```
#### `response-policy`
**v9.18.44**:
```
{ zone <string> [ add-soa <boolean> ] [ log <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only <quoted_string> ) ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ]
```
**v9.20.18**:
```
{ zone <string> [ add-soa <boolean> ] [ log <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only <quoted_string> ) ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ ede <string> ]
```
#### `cookie-algorithm`
**v9.18.44**:
```
( aes | siphash24 )
```
**v9.20.18**:
```
( siphash24 )
```
#### `forwarders`
**v9.18.44**:
```
[ port <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ]
```
**v9.20.18**:
```
[ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]
```
#### `listen-on-v6`
**v9.18.44**:
```
[ port <integer> ] [ tls <string> ] [ http <string> ] { <address_match_element>
```
**v9.20.18**:
```
[ port <integer> ] [ proxy <string> ] [ tls <string> ] [ http <string> ] { <address_match_element>
```
#### `also-notify`
**v9.18.44**:
```
[ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
**v9.20.18**:
```
[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
#### `catalog-zones`
**v9.18.44**:
```
{ zone <string> [ default-primaries [ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
**v9.20.18**:
```
{ zone <string> [ default-primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
### forward.zoneopt
#### `forwarders`
**v9.18.44**:
```
[ port <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ]
```
**v9.20.18**:
```
[ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]
```
### mirror.zoneopt
#### `also-notify`
**v9.18.44**:
```
[ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
**v9.20.18**:
```
[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
#### `primaries`
**v9.18.44**:
```
[ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
**v9.20.18**:
```
[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
### primary.zoneopt
#### `update-policy`
**v9.18.44**:
```
( local | { ( deny | grant ) <string> ( 6to4-self | external | krb5-self | krb5-selfsub | krb5-subdomain | krb5-subdomain-self-rhs | ms-self | ms-selfsub | ms-subdomain | ms-subdomain-self-rhs | name | self | selfsub | selfwild | subdomain | tcp-self | wildcard | zonesubject ) [ <string> ] <rrtype list>
```
**v9.20.18**:
```
( local | { ( deny | grant ) <string> ( 6to4-self | external | krb5-self | krb5-selfsub | krb5-subdomain | krb5-subdomain-self-rhs | ms-self | ms-selfsub | ms-subdomain | ms-subdomain-self-rhs | name | self | selfsub | selfwild | subdomain | tcp-self | wildcard | zonesub ) [ <string> ] <rrtype list>
```
#### `also-notify`
**v9.18.44**:
```
[ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
**v9.20.18**:
```
[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
#### `parental-agents`
**v9.18.44**:
```
[ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
**v9.20.18**:
```
[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
#### `forwarders`
**v9.18.44**:
```
[ port <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ]
```
**v9.20.18**:
```
[ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]
```
### redirect.zoneopt
#### `primaries`
**v9.18.44**:
```
[ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
**v9.20.18**:
```
[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
### secondary.zoneopt
#### `also-notify`
**v9.18.44**:
```
[ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
**v9.20.18**:
```
[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
#### `parental-agents`
**v9.18.44**:
```
[ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
**v9.20.18**:
```
[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
#### `forwarders`
**v9.18.44**:
```
[ port <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ]
```
**v9.20.18**:
```
[ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]
```
#### `primaries`
**v9.18.44**:
```
[ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
**v9.20.18**:
```
[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
### static-stub.zoneopt
#### `forwarders`
**v9.18.44**:
```
[ port <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ]
```
**v9.20.18**:
```
[ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]
```
### stub.zoneopt
#### `forwarders`
**v9.18.44**:
```
[ port <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ]
```
**v9.20.18**:
```
[ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]
```
#### `primaries`
**v9.18.44**:
```
[ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
**v9.20.18**:
```
[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]
```
## 📋 Newly Deprecated Options
The following options were marked as deprecated in v9.20.18:
### options
- `sortlist`
### primary.zoneopt
- `max-zone-ttl`
### redirect.zoneopt
- `max-zone-ttl`
## Detailed File-by-File Comparison
### options
- v9.18.44: 334 options
- v9.20.18: 333 options
- Added: 26
- Removed: 27
- Modified: 7
### forward.zoneopt
- v9.18.44: 5 options
- v9.20.18: 4 options
- Added: 0
- Removed: 1
- Modified: 1
### hint.zoneopt
- v9.18.44: 5 options
- v9.20.18: 4 options
- Added: 0
- Removed: 1
- Modified: 0
### in-view.zoneopt
- v9.18.44: 2 options
- v9.20.18: 2 options
- Added: 0
- Removed: 0
- Modified: 0
### mirror.zoneopt
- v9.18.44: 44 options
- v9.20.18: 43 options
- Added: 2
- Removed: 3
- Modified: 2
### primary.zoneopt
- v9.18.44: 63 options
- v9.20.18: 62 options
- Added: 3
- Removed: 4
- Modified: 4
### redirect.zoneopt
- v9.18.44: 14 options
- v9.20.18: 14 options
- Added: 0
- Removed: 0
- Modified: 1
### secondary.zoneopt
- v9.18.44: 66 options
- v9.20.18: 65 options
- Added: 3
- Removed: 4
- Modified: 4
### static-stub.zoneopt
- v9.18.44: 12 options
- v9.20.18: 12 options
- Added: 0
- Removed: 0
- Modified: 1
### stub.zoneopt
- v9.18.44: 28 options
- v9.20.18: 27 options
- Added: 1
- Removed: 2
- Modified: 2
### delegation-only.zoneopt
- v9.18.44: 2 options
- v9.20.18: 0 options
- Added: 0
- Removed: 2
- Modified: 0
### rndc.grammar
- v9.18.44: 14 options
- v9.20.18: 14 options
- Added: 0
- Removed: 0
- Modified: 0
## Migration Guide
### Migrating from v9.18.44 to v9.20.18
1. **Remove unsupported options** from your configuration
- Review the Breaking Changes section above
- Check if there are replacement options
2. **Plan for deprecated options**
- These options still work but may be removed in future versions
- Start planning migration to recommended alternatives
3. **Test your configuration**
- Use `named-checkconf` to validate syntax
- Test in a development environment before production

370
docs/VERSION_SUPPORT.md Normal file
View File

@@ -0,0 +1,370 @@
# BIND9 Version Support Policy
**Document Version**: 1.0
**Last Updated**: 2026-02-07
**Role Version**: Current development
## Overview
This document defines the version maintenance strategy for the ansible-bind9-role, including supported BIND9 versions, OS platforms, branching strategy, and release management policies.
## Supported Versions
### BIND9 Versions
| BIND9 Version | Branch | Status | Support Level | EOL Date |
|---------------|--------|--------|---------------|----------|
| 9.18.x (LTS) | `main` | ✅ Active | Full support | TBD (following ISC LTS timeline) |
| 9.20.x+ | `9.20` | 🚧 In Development | Planned | N/A |
#### Version Selection Rationale
- **BIND9 9.18**: Long Term Support (LTS) release from ISC
- Maintained by ISC with extended support timeline
- Stable feature set suitable for production environments
- Current focus of this role
- **BIND9 9.20+**: Feature release series
- Introduces significant configuration changes
- New features and modernization
- May have shorter support windows per release
- Will be supported in separate branch to prevent breaking changes
### Operating System Support Matrix
| OS Distribution | Versions | BIND9 9.18 | BIND9 9.20+ | Notes |
|----------------|----------|------------|-------------|-------|
| Debian | 11 (Bullseye) | ✅ Supported | 🔍 Testing | Current stable |
| Debian | 12 (Bookworm) | ✅ Supported | ✅ Supported | Current testing focus |
| Debian | 13 (Trixie) | ✅ Supported | ✅ Supported | Future stable |
| Ubuntu | 20.04 LTS | ✅ Supported | 🔍 Testing | LTS until 2025 |
| Ubuntu | 22.04 LTS | ✅ Supported | ✅ Supported | LTS until 2027 |
| Ubuntu | 24.04 LTS | ✅ Supported | ✅ Supported | LTS until 2029 |
**Legend**:
- ✅ Supported: Fully tested and supported
- 🔍 Testing: In testing, use with caution
- ⚠️ Limited: Basic support only
- ❌ Unsupported: Not supported
### Minimum Requirements
- **Ansible**: 2.13 or later
- **Python**: 3.8 or later (on controller and managed nodes)
- **BIND9 Packages**: Must be available in distribution repositories or custom sources
## Branching Strategy
### Branch Structure
```
main # BIND9 9.18 LTS (stable)
├── 9.20 # BIND9 9.20+ development
├── docs # Documentation updates (merged to both)
└── feature/* # Feature branches (target appropriate base)
```
### Branch Policies
#### `main` Branch
- **Purpose**: Production-ready code for BIND9 9.18 LTS
- **Stability**: Stable, tested releases only
- **Breaking Changes**: Not allowed
- **Version Tagging**: `v1.x.x`, `v2.x.x`, etc.
#### `9.20` Branch
- **Purpose**: Development for BIND9 9.20+ support
- **Stability**: Development/testing phase
- **Breaking Changes**: Allowed (vs 9.18 configurations)
- **Version Tagging**: `v9.20.x-betaX`, `v9.20.x-rcX`, `v9.20.x`
#### Feature Branches
- **Naming**: `feature/description` or `fix/issue-number`
- **Target**: Merge to appropriate base (`main` for 9.18, `9.20` for 9.20+)
- **Lifecycle**: Delete after merge
### Backporting Policy
#### Security Fixes
- **Policy**: MUST be backported to all supported branches
- **Timeline**: Within 48 hours of fix
- **Priority**: Critical
#### Bug Fixes
- **Policy**: SHOULD be backported if:
- Affects both versions
- Low risk of introducing regressions
- Reasonable effort required
- **Timeline**: Within 1 week
- **Priority**: High
#### New Features
- **Policy**: Case-by-case evaluation
- **Criteria**:
- Feature is compatible with both BIND9 versions
- Does not introduce breaking changes
- Provides significant value
- Low implementation complexity
- **Timeline**: Best effort
- **Priority**: Medium
#### Breaking Changes
- **Policy**: NEVER backported
- **Implementation**: Only in version-specific branches
## Release Management
### Version Numbering
Following [Semantic Versioning 2.0.0](https://semver.org/):
```
MAJOR.MINOR.PATCH
MAJOR: Incompatible API changes (role variable structure changes)
MINOR: New functionality in a backwards compatible manner
PATCH: Backwards compatible bug fixes
```
#### Examples
- `v1.2.3`: Patch release for BIND9 9.18
- `v2.0.0`: Major release with breaking role variable changes
- `v9.20.0-beta1`: Beta release for BIND9 9.20 support
- `v9.20.0`: First stable release for BIND9 9.20
### Release Cadence
- **Patch Releases**: As needed for bug fixes and security updates
- **Minor Releases**: Quarterly (or when significant features accumulate)
- **Major Releases**: Annually (or when breaking changes are necessary)
### Pre-release Testing
All releases must pass:
1. **Molecule tests** across all supported platforms
2. **named-checkconf** validation for all example configurations
3. **Manual testing** on at least 2 different distributions
4. **Documentation review** and update
### Release Checklist
- [ ] Update `CHANGELOG.md` with all changes
- [ ] Update version in `meta/main.yml`
- [ ] Run full molecule test suite
- [ ] Update `README.md` if needed
- [ ] Create annotated git tag
- [ ] Push tag to trigger CI/CD
- [ ] Create GitHub/Gitea release with notes
- [ ] Announce on project channels
## Testing Strategy
### Test Matrix
#### Molecule Scenarios
| Scenario | Distribution | BIND9 Version | Purpose |
|----------|--------------|---------------|---------|
| default | Debian 13 | 9.18 | Primary development testing |
| ubuntu2204 | Ubuntu 22.04 | 9.18 | LTS testing |
| ubuntu2404 | Ubuntu 24.04 | 9.18/9.20 | Future-proofing |
| debian12 | Debian 12 | 9.18 | Stable release testing |
#### Test Coverage
- **Syntax validation**: All templates pass `named-checkconf`
- **Service management**: Start, stop, reload, restart operations
- **Configuration types**: All zone types and statement blocks
- **Edge cases**: Empty configurations, complex nested structures
- **Upgrade scenarios**: Migration from previous role versions
### Continuous Integration
```yaml
# .github/workflows/test.yml (example structure)
on: [push, pull_request]
jobs:
molecule:
strategy:
matrix:
distro: [debian12, debian13, ubuntu2204, ubuntu2404]
bind_version: ['9.18', '9.20']
exclude:
# Don't test 9.20 on older distributions
- distro: ubuntu2004
bind_version: '9.20'
```
## Grammar Tracking and Validation
### Automated Grammar Comparison
The role maintains upstream BIND9 grammar files to:
1. Detect configuration syntax changes between versions
2. Identify deprecated and removed options
3. Document breaking changes for users
#### Grammar Repository Structure
```
bind9-grammar/
├── upstream/
│ ├── v9.18.44/ # Latest 9.18 LTS grammar
│ │ ├── grammar/
│ │ │ ├── options
│ │ │ ├── *.zoneopt
│ │ │ └── parsegrammar.py
│ │ └── metadata.json
│ └── v9.20.18/ # Latest 9.20 grammar
│ ├── grammar/
│ └── metadata.json
├── 9.18/ # Current 9.18 JSON schemas
│ └── *.json
└── 9.20/ # Future 9.20 JSON schemas
└── *.json
```
### Validation Tools
#### `scripts/fetch_bind_grammar.py`
- Fetches grammar files from Gitea mirror (`Mirrors/bind9`)
- Supports version tags (e.g., `v9.18.44`, `v9.20.18`)
- Stores upstream grammar for comparison
#### `scripts/compare_bind_versions.py`
- Compares grammar files between versions
- Generates `docs/BIND_VERSION_DIFFERENCES.md`
- Identifies:
- Breaking changes (removed options)
- New features (added options)
- Modified syntax
- Deprecation notices
### Grammar Update Workflow
1. **Monitor**: Watch Gitea mirror for new BIND9 releases
2. **Fetch**: Run `fetch_bind_grammar.py` for new version
3. **Compare**: Run `compare_bind_versions.py` to identify changes
4. **Review**: Analyze breaking changes and impact
5. **Update**: Modify templates and variables as needed
6. **Test**: Run molecule tests with new version
7. **Document**: Update `BIND_VERSION_DIFFERENCES.md` and `CHANGELOG.md`
## Deprecation Policy
### Deprecation Process
1. **Announcement**: Document deprecation in `CHANGELOG.md` and `README.md`
2. **Warning Period**: Minimum 2 minor releases before removal
3. **Alternative**: Provide migration path or alternative approach
4. **Removal**: Only in major version releases
### Current Deprecations
*None at this time*
### Planned Deprecations
*To be determined based on BIND9 9.20 analysis*
## Version-Specific Features
### Version Detection
The role will detect BIND9 version at runtime:
```yaml
# tasks/main.yml (planned implementation)
- name: Detect BIND9 version
ansible.builtin.command: named -V
register: _bind9_version_output
changed_when: false
- name: Set BIND9 version facts
ansible.builtin.set_fact:
bind9_version_full: "{{ _bind9_version_output.stdout | regex_search('BIND (\\S+)', '\\1') | first }}"
bind9_version_major: "{{ _bind9_version_output.stdout | regex_search('BIND (\\d+)\\.(\\d+)', '\\1') | first }}"
bind9_version_minor: "{{ _bind9_version_output.stdout | regex_search('BIND (\\d+)\\.(\\d+)', '\\2') | first }}"
```
### Conditional Configuration
Templates will use version-aware conditionals:
```jinja2
{# templates/named.conf.options.j2 (planned) #}
{% if bind9_version_major | int >= 20 %}
{# BIND9 9.20+ specific options #}
{% else %}
{# BIND9 9.18 options #}
{% endif %}
```
## Migration Guidance
### Migrating from BIND9 9.18 to 9.20
When BIND9 9.20 support is released:
1. **Review**: Read `docs/BIND_VERSION_DIFFERENCES.md`
2. **Test**: Use `9.20` branch in test environment
3. **Update**: Modify playbook variables for deprecated/removed options
4. **Validate**: Run `named-checkconf` against generated configuration
5. **Deploy**: Upgrade BIND9 package and deploy new configuration
6. **Monitor**: Check logs for warnings or errors
### Migrating Between Role Versions
See `CHANGELOG.md` for version-specific migration notes.
## Support and Contribution
### Getting Help
- **Issues**: Report bugs and request features on Gitea
- **Documentation**: Refer to `README.md` and `CONFIGURATION_GRAMMAR.md`
- **Examples**: Check `tests/` directory for working configurations
### Contributing
- **Bug Fixes**: Target `main` branch (or `9.20` if version-specific)
- **Features**: Discuss in issue before implementation
- **Testing**: Ensure molecule tests pass
- **Documentation**: Update relevant documentation files
### Governance
- **Maintainer**: Primary maintainer approves all merges
- **Review**: All changes require review before merge
- **Testing**: CI/CD must pass before merge
## Future Considerations
### BIND9 9.21+ and Beyond
- Monitor ISC release announcements
- Evaluate need for additional branches
- Consider dropping support for EOL'd distributions
- Reassess branching strategy if maintenance burden increases
### Automation Improvements
- Automated grammar fetching in CI
- Automated breaking change detection
- Version compatibility testing matrix
- Documentation generation from grammar files
## References
- [ISC BIND9 Documentation](https://bind9.readthedocs.io/)
- [ISC BIND9 Release Schedule](https://www.isc.org/bind/)
- [Semantic Versioning](https://semver.org/)
- [Ansible Best Practices](https://docs.ansible.com/ansible/latest/tips_tricks/ansible_tips_tricks.html)
## Changelog
| Date | Version | Changes |
|------|---------|---------|
| 2026-02-07 | 1.0 | Initial version support policy |

View File

@@ -0,0 +1,326 @@
{
"options": {
"file": "options",
"added": [
"allow-proxy",
"allow-proxy-on",
"cdnskey",
"cds-digest-types",
"check-svcb",
"cipher-suites",
"dnsrps-library",
"inline-signing",
"key-store",
"manual-mode",
"max-validation-failures-per-fetch",
"max-validations-per-fetch",
"min-transfer-rate-in",
"notify-defer",
"offline-ksk",
"pkcs11-uri",
"recursing-file",
"remote-servers",
"require-cookie",
"resolver-use-dns64",
"responselog",
"reuseport",
"sig0-checks-quota",
"sig0-checks-quota-exempt",
"sig0-key-checks-limit",
"sig0-message-checks-limit"
],
"removed": [
"alt-transfer-source",
"alt-transfer-source-v6",
"auto-dnssec",
"coresize",
"datasize",
"dscp",
"files",
"glue-cache",
"heartbeat-interval",
"keep-response-order",
"lock-file",
"maxz-zone-ttl",
"parent-registration-delay",
"parental-agents",
"primaries",
"random-device",
"recurse-ing-file",
"reserved-sockets",
"resolver-nonbackoff-tries",
"resolver-retry-interval",
"reuse",
"root-delegation-only",
"stacksize",
"suppress-initial-notify",
"tkey-dhkey",
"tkey-gssapi-credential",
"use-alt-transfer-source"
],
"modified": [
{
"option": "listen-on",
"old_definition": "[ port <integer> ] [ tls <string> ] [ http <string> ] { <address_match_element>",
"new_definition": "[ port <integer> ] [ proxy <string> ] [ tls <string> ] [ http <string> ] { <address_match_element>"
},
{
"option": "response-policy",
"old_definition": "{ zone <string> [ add-soa <boolean> ] [ log <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only <quoted_string> ) ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ]",
"new_definition": "{ zone <string> [ add-soa <boolean> ] [ log <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only <quoted_string> ) ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ ede <string> ]"
},
{
"option": "cookie-algorithm",
"old_definition": "( aes | siphash24 )",
"new_definition": "( siphash24 )"
},
{
"option": "forwarders",
"old_definition": "[ port <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ]",
"new_definition": "[ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]"
},
{
"option": "listen-on-v6",
"old_definition": "[ port <integer> ] [ tls <string> ] [ http <string> ] { <address_match_element>",
"new_definition": "[ port <integer> ] [ proxy <string> ] [ tls <string> ] [ http <string> ] { <address_match_element>"
},
{
"option": "also-notify",
"old_definition": "[ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]",
"new_definition": "[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]"
},
{
"option": "catalog-zones",
"old_definition": "{ zone <string> [ default-primaries [ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]",
"new_definition": "{ zone <string> [ default-primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]"
}
],
"deprecated_new": [
"sortlist"
],
"options1_count": 334,
"options2_count": 333
},
"forward.zoneopt": {
"file": "forward.zoneopt",
"added": [],
"removed": [
"delegation-only"
],
"modified": [
{
"option": "forwarders",
"old_definition": "[ port <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ]",
"new_definition": "[ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]"
}
],
"deprecated_new": [],
"options1_count": 5,
"options2_count": 4
},
"hint.zoneopt": {
"file": "hint.zoneopt",
"added": [],
"removed": [
"delegation-only"
],
"modified": [],
"deprecated_new": [],
"options1_count": 5,
"options2_count": 4
},
"in-view.zoneopt": {
"file": "in-view.zoneopt",
"added": [],
"removed": [],
"modified": [],
"deprecated_new": [],
"options1_count": 2,
"options2_count": 2
},
"mirror.zoneopt": {
"file": "mirror.zoneopt",
"added": [
"min-transfer-rate-in",
"notify-defer"
],
"removed": [
"alt-transfer-source",
"alt-transfer-source-v6",
"use-alt-transfer-source"
],
"modified": [
{
"option": "also-notify",
"old_definition": "[ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]",
"new_definition": "[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]"
},
{
"option": "primaries",
"old_definition": "[ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]",
"new_definition": "[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]"
}
],
"deprecated_new": [],
"options1_count": 44,
"options2_count": 43
},
"primary.zoneopt": {
"file": "primary.zoneopt",
"added": [
"check-svcb",
"checkds",
"notify-defer"
],
"removed": [
"alt-transfer-source",
"alt-transfer-source-v6",
"auto-dnssec",
"update-check-ksk"
],
"modified": [
{
"option": "update-policy",
"old_definition": "( local | { ( deny | grant ) <string> ( 6to4-self | external | krb5-self | krb5-selfsub | krb5-subdomain | krb5-subdomain-self-rhs | ms-self | ms-selfsub | ms-subdomain | ms-subdomain-self-rhs | name | self | selfsub | selfwild | subdomain | tcp-self | wildcard | zonesubject ) [ <string> ] <rrtype list>",
"new_definition": "( local | { ( deny | grant ) <string> ( 6to4-self | external | krb5-self | krb5-selfsub | krb5-subdomain | krb5-subdomain-self-rhs | ms-self | ms-selfsub | ms-subdomain | ms-subdomain-self-rhs | name | self | selfsub | selfwild | subdomain | tcp-self | wildcard | zonesub ) [ <string> ] <rrtype list>"
},
{
"option": "also-notify",
"old_definition": "[ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]",
"new_definition": "[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]"
},
{
"option": "parental-agents",
"old_definition": "[ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]",
"new_definition": "[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]"
},
{
"option": "forwarders",
"old_definition": "[ port <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ]",
"new_definition": "[ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]"
}
],
"deprecated_new": [
"max-zone-ttl"
],
"options1_count": 63,
"options2_count": 62
},
"redirect.zoneopt": {
"file": "redirect.zoneopt",
"added": [],
"removed": [],
"modified": [
{
"option": "primaries",
"old_definition": "[ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]",
"new_definition": "[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]"
}
],
"deprecated_new": [
"max-zone-ttl"
],
"options1_count": 14,
"options2_count": 14
},
"secondary.zoneopt": {
"file": "secondary.zoneopt",
"added": [
"checkds",
"min-transfer-rate-in",
"notify-defer"
],
"removed": [
"alt-transfer-source",
"alt-transfer-source-v6",
"auto-dnssec",
"use-alt-transfer-source"
],
"modified": [
{
"option": "also-notify",
"old_definition": "[ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]",
"new_definition": "[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]"
},
{
"option": "parental-agents",
"old_definition": "[ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]",
"new_definition": "[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]"
},
{
"option": "forwarders",
"old_definition": "[ port <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ]",
"new_definition": "[ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]"
},
{
"option": "primaries",
"old_definition": "[ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]",
"new_definition": "[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]"
}
],
"deprecated_new": [],
"options1_count": 66,
"options2_count": 65
},
"static-stub.zoneopt": {
"file": "static-stub.zoneopt",
"added": [],
"removed": [],
"modified": [
{
"option": "forwarders",
"old_definition": "[ port <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ]",
"new_definition": "[ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]"
}
],
"deprecated_new": [],
"options1_count": 12,
"options2_count": 12
},
"stub.zoneopt": {
"file": "stub.zoneopt",
"added": [
"min-transfer-rate-in"
],
"removed": [
"delegation-only",
"use-alt-transfer-source"
],
"modified": [
{
"option": "forwarders",
"old_definition": "[ port <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ]",
"new_definition": "[ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]"
},
{
"option": "primaries",
"old_definition": "[ port <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]",
"new_definition": "[ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]"
}
],
"deprecated_new": [],
"options1_count": 28,
"options2_count": 27
},
"delegation-only.zoneopt": {
"file": "delegation-only.zoneopt",
"added": [],
"removed": [
"type",
"zone"
],
"modified": [],
"deprecated_new": [],
"options1_count": 2,
"options2_count": 0
},
"rndc.grammar": {
"file": "rndc.grammar",
"added": [],
"removed": [],
"modified": [],
"deprecated_new": [],
"options1_count": 14,
"options2_count": 14
}
}

View File

@@ -16,10 +16,8 @@
- "{{ bind9_cfgdir }}" - "{{ bind9_cfgdir }}"
- "{{ bind9_working_directory }}" - "{{ bind9_working_directory }}"
- "{{ bind9_libdir }}" - "{{ bind9_libdir }}"
dest: "{{ dest: "{{ bind9_backup_dir + '/bind9-config-' + ansible_facts.date_time.iso8601_basic_short + '.tar.gz' }}"
bind9_backup_dir + '/bind9-config-' +
ansible_facts.date_time.iso8601_basic_short + '.tar.gz' }}"
owner: root owner: root
group: root group: root
mode: 0640 mode: "0640"
when: bind9_backup_config is defined and bind9_backup_config when: bind9_backup_config is defined and bind9_backup_config

View File

@@ -2,6 +2,10 @@
argument_specs: argument_specs:
main: main:
short_description: The main entry point for the bind9 role. short_description: The main entry point for the bind9 role.
description:
- Configures BIND9 DNS server on Debian-based systems.
- "Supported BIND9 versions: 9.18.x (LTS), 9.20+ (feature releases)"
- Version detection is automatic at runtime.
options: options:
bind9_config: bind9_config:
type: list type: list
@@ -53,3 +57,10 @@ argument_specs:
bind9_backup_dir: bind9_backup_dir:
type: str type: str
description: Directory for backups. description: Directory for backups.
bind9_version:
type: str
description:
- BIND9 version detected at runtime (read-only, set automatically).
- "Format: X.Y.Z (e.g., 9.18.44, 9.20.18)"
- Used by templates to apply version-specific configurations.
- Users should not set this variable directly.

View File

@@ -7,7 +7,7 @@ galaxy_info:
description: Configure Bind9 description: Configure Bind9
company: Valid.dk company: Valid.dk
issue_tracker_url: https://gitlab.valid.dk/operations/ansible-bind9-role issue_tracker_url: https://git.valid.dk/daniel/ansible-bind9-role
license: GPL-3.0-or-later license: GPL-3.0-or-later

108
molecule/bind9-20/README.md Normal file
View File

@@ -0,0 +1,108 @@
# BIND9 9.20 Molecule Scenario
This Molecule scenario validates the ansible-bind9-role with BIND9 9.20 and later feature releases.
## Purpose
- Tests role compatibility with BIND9 9.20+ which includes 44 breaking changes from 9.18.x
- Validates version-specific templates and configurations
- Ensures configuration syntax is correct for newer BIND9 versions
- Documents 9.20-specific configuration patterns
## Platform
- **Base Image**: Ubuntu 24.04 LTS (docker.io/library/ubuntu:24.04)
- **BIND9 Version**: 9.20.x or later (as available in Ubuntu 24.04 repositories)
## Notable BIND9 9.20 Changes
Key breaking changes in this scenario:
1. **Automatic Options**: The following options are automatically enabled in 9.20 and should not be configured:
- `glue-cache` - Always enabled
- `keep-response-order` - Always enabled
- `reuse` - Always enabled
- `recursion-enabled` - Always enabled
2. **Removed Options**: These options are no longer supported in 9.20:
- `alt-transfer-source` - Use TLS instead
- `alt-transfer-source-v6` - Use TLS instead
- `auto-dnssec` - DNSSEC management is automatic
- `dsc` - Use TLS configuration instead
- `gssapi-credential` - Use TSIG + TLS instead
- `heartbeat-interval` - Zone transfer monitoring changed
- `lock-file` - OS-level locking is used
- `root-delegation-only` - Use zone constraints instead
3. **Enhanced Features**:
- Improved TLS/DoT support for zone transfers
- Native DNSSEC management
- Better resolver behavior and retry logic
- Native HTTP/HTTPS server capabilities
## Configuration Features Tested
- **DNS Forwarding**: Forward zones with TLS-based forwarders (DoT)
- **Query Logging**: Detailed query and response logging
- **DNSTAP**: DNS packet capture for forensics
- **TLS Configuration**: Modern TLS configurations for zone transfers
- **Recursion**: Proper recursion configuration with ACLs
- **DNSSEC Validation**: Modern DNSSEC validation approach
## Testing
To run this scenario:
```bash
# Test with this specific scenario
cd /path/to/ansible-bind9-role
molecule test -s bind9-20
# Or specific steps
molecule create -s bind9-20
molecule converge -s bind9-20
molecule verify -s bind9-20
molecule destroy -s bind9-20
```
## Expected Results
- BIND9 service starts successfully
- Configuration files are generated without errors
- DNS forwarding works correctly
- Named-checkconf validates the configuration
- All log channels are operational
- TLS connections are established for forwarders
## Troubleshooting
### BIND9 Package Not Available
If BIND9 9.20 is not available in Ubuntu 24.04 repositories, you may need to:
1. Build from source using the upstream ISC BIND9 repository
2. Use a different base image with more recent BIND9 packages
3. Add a custom APT repository with backported packages
### Configuration Syntax Errors
Review `/etc/bind/named.conf` using:
```bash
named-checkconf /etc/bind/named.conf
```
Check logs at `/var/log/named/default.log` for specific error messages.
## Future Updates
- [ ] Add support for BIND9 9.20 DNS-over-HTTPS (DoH)
- [ ] Test with BIND9 9.22+ when released
- [ ] Validate performance improvements
- [ ] Test clustering/replication features
## References
- [BIND9 Documentation](https://bind9.readthedocs.io/)
- [BIND9 9.20 Release Notes](https://www.isc.org/bind/)
- [DNS-over-TLS (DoT) RFC 7858](https://tools.ietf.org/html/rfc7858)

View File

@@ -0,0 +1,4 @@
---
collections:
- ansible.posix
- community.general

View File

@@ -0,0 +1,122 @@
---
- name: Converge
hosts: all
tasks:
- name: Create log directory for BIND
ansible.builtin.file:
path: /var/log/named
state: directory
mode: '0755'
owner: bind
group: bind
- name: Include bind9 role
ansible.builtin.include_role:
name: ../../../ansible-bind9-role # noqa: role-name[path]
vars:
bind9_backup_config: false
# BIND9 9.20+ configuration with version-specific options
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
dnstap:
- type: auth
- type: resolver
log: query
- type: client
log: response
dnstap_output:
output_type: file
output_file: /var/log/named/dnstap.log
size: 20m
versions: 3
suffix: increment
dnstap_identity: dns-server-01
dnstap_version: 9.20
# Note: BIND9 9.20 automatically enables glue-cache, keep-response-order, reuse
# These options are removed in 9.20 and should not be configured
# Removed options (9.18 compatibility note):
# - alt_transfer_source (use TLS instead)
# - auto_dnssec (automatic in 9.20)
# - glue_cache (always enabled in 9.20)
logging:
channels:
- name: default_log
file:
name: /var/log/named/default.log
severity: info
print_time: true
print_severity: true
print_category: true
- name: security_log
file:
name: /var/log/named/security.log
severity: dynamic
print_time: true
print_severity: true
print_category: true
- name: query_log
file:
name: /var/log/named/queries.log
versions: 5
size: 10m
severity: info
print_time: true
- name: dnssec_log
file:
name: /var/log/named/dnssec.log
severity: debug
print_time: true
print_severity: true
- name: rate_limit_log
syslog: daemon
severity: warning
categories:
- name: default
channels:
- default_log
- name: general
channels:
- default_log
- name: security
channels:
- security_log
- name: queries
channels:
- query_log
- name: dnssec
channels:
- dnssec_log
- name: rate-limit
channels:
- rate_limit_log
- 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

@@ -0,0 +1,22 @@
---
# Molecule scenario for BIND9 9.20+ support validation
# This scenario tests the role with BIND9 9.20 and later feature releases
# Note: May require ubuntu:24.04 or Debian 13 (Trixie) for 9.20 package availability
driver:
name: podman
platforms:
- name: ubuntu-2404-bind920
image: docker.io/library/ubuntu:24.04
command: /lib/systemd/systemd
privileged: true
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw
cgroupns_mode: host
provisioner:
name: ansible
config_options:
defaults:
ALLOW_BROKEN_CONDITIONALS: true
verifier:
name: ansible

View File

@@ -0,0 +1,14 @@
---
- name: Prepare
hosts: all
tasks:
- name: Update package cache
ansible.builtin.apt:
update_cache: true
- name: Install DNS query tools (dnsutils)
ansible.builtin.apt:
name:
- dnsutils
- bind9-doc
state: present

View File

@@ -0,0 +1,120 @@
---
- 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 BIND9 version is 9.20 or later
ansible.builtin.command:
cmd: named -v
register: __bind9_version_check
changed_when: false
failed_when: false
- name: Display BIND9 version
ansible.builtin.debug:
msg: "BIND9 version: {{ __bind9_version_check.stdout }}"
- 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"
- "'91.239.100.100' 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
- name: Validate configuration syntax with named-checkconf
ansible.builtin.command:
cmd: named-checkconf /etc/bind/named.conf
register: __named_checkconf
changed_when: false
failed_when: __named_checkconf.rc != 0
- name: Check BIND logs for errors
ansible.builtin.command:
cmd: tail -30 /var/log/named/default.log
register: __bind_logs
changed_when: false
- name: Display BIND logs
ansible.builtin.debug:
msg: "BIND logs:\n{{ __bind_logs.stdout }}"
- name: Verify no critical errors in logs
ansible.builtin.shell: |
set -o pipefail
if grep -i "error" /var/log/named/default.log | grep -v "error reporting" > /dev/null; then
exit 1
fi
changed_when: false
failed_when: false
register: __error_check
- name: Assert no critical errors found
ansible.builtin.assert:
that:
- __error_check.rc == 0
fail_msg: Found critical errors in BIND logs

View File

@@ -4,4 +4,3 @@ collections:
- name: ansible.posix - name: ansible.posix
- name: community.crypto - name: community.crypto
- name: community.general - name: community.general

View File

@@ -4,4 +4,116 @@
tasks: tasks:
- name: Include bind9 role - name: Include bind9 role
ansible.builtin.include_role: ansible.builtin.include_role:
name: ../../../ansible-bind9-role name: ../../../ansible-bind9-role # noqa: role-name[path]
vars:
bind9_log_dir: /var/log/named
bind9_backup_config: false
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
dnstap:
- type: auth
- type: resolver
log: query
- type: client
log: response
dnstap_output:
output_type: file
output_file: /var/log/named/dnstap.log
size: 20m
versions: 3
suffix: increment
dnstap_identity: dns-server-01
dnstap_version: 9.18
logging:
channels:
- name: default_log
file:
name: /var/log/named/default.log
severity: info
print_time: true
print_severity: true
print_category: true
- name: security_log
file:
name: /var/log/named/security.log
severity: dynamic
print_time: true
print_severity: true
print_category: true
- name: query_log
file:
name: /var/log/named/queries.log
versions: 5
size: 10m
severity: info
print_time: true
- name: dnssec_log
file:
name: /var/log/named/dnssec.log
severity: debug
print_time: true
print_severity: true
- name: rate_limit_log
syslog: daemon
severity: warning
categories:
- name: default
channels:
- default_log
- name: general
channels:
- default_log
- name: security
channels:
- security_log
- name: queries
channels:
- query_log
- name: dnssec
channels:
- dnssec_log
- name: rate-limit
channels:
- rate_limit_log
- 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
- name: Post-converge
hosts: all
tasks:
- name: Create log directory for BIND
ansible.builtin.file:
path: /var/log/named
state: directory
mode: '0750'
owner: bind
group: bind

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

@@ -1,6 +1,11 @@
--- ---
- hosts: all - name: Prepare
hosts: all
tasks: tasks:
- 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,77 @@
---
- 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"
- "'91.239.100.100' in __options_decoded"
- "'89.233.43.71' 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

@@ -0,0 +1,390 @@
#!/usr/bin/env python3
"""
Compare BIND9 grammar files between versions to identify breaking changes.
This script compares grammar files from two BIND9 versions and generates
a comprehensive report of:
- Removed options (breaking changes)
- Added options (new features)
- Modified option syntax
- Deprecated options
Usage:
python scripts/compare_bind_versions.py \\
--version1-dir bind9-grammar/upstream/v9.18.44 \\
--version2-dir bind9-grammar/upstream/v9.20.18 \\
--output docs/BIND_VERSION_DIFFERENCES.md
"""
import argparse
import json
import sys
from pathlib import Path
from typing import Dict, List, Set, Tuple
import re
class GrammarComparator:
"""Compare BIND9 grammar files between versions."""
def __init__(self, version1_dir: Path, version2_dir: Path):
"""
Initialize comparator with two version directories.
Args:
version1_dir: Path to first version's grammar files
version2_dir: Path to second version's grammar files
"""
self.version1_dir = version1_dir
self.version2_dir = version2_dir
self.version1_name = version1_dir.name
self.version2_name = version2_dir.name
def load_grammar_file(self, file_path: Path) -> Dict:
"""Load and parse a grammar file."""
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
# Parse grammar file into structured data
options = self._parse_grammar(content)
return options
except FileNotFoundError:
return {}
def _parse_grammar(self, content: str) -> Dict[str, str]:
"""
Parse grammar content into a dictionary of options.
This is a simplified parser that extracts top-level keywords
and their definitions.
"""
options = {}
lines = content.split('\n')
for line in lines:
line = line.strip()
if not line or line.startswith('#') or line.startswith('//'):
continue
# Extract keyword and its definition
# Pattern: keyword <definition>; or keyword <definition> { ... };
match = re.match(r'^([a-z0-9-]+)\s+(.+?)(?:;|$)', line)
if match:
keyword = match.group(1)
definition = match.group(2).strip()
# Extract flags from comments
flags = []
if '// may occur multiple times' in line:
flags.append('may occur multiple times')
if '// deprecated' in line:
flags.append('deprecated')
if '// obsolete' in line:
flags.append('obsolete')
if '// not configured' in line:
flags.append('not configured')
if '// test only' in line:
flags.append('test only')
if '// experimental' in line:
flags.append('experimental')
options[keyword] = {
'definition': definition,
'flags': flags,
'raw_line': line
}
return options
def compare_files(self, filename: str) -> Dict:
"""
Compare a specific grammar file between two versions.
Returns:
Dict with added, removed, modified, and deprecated options
"""
file1 = self.version1_dir / 'grammar' / filename
file2 = self.version2_dir / 'grammar' / filename
options1 = self.load_grammar_file(file1)
options2 = self.load_grammar_file(file2)
keys1 = set(options1.keys())
keys2 = set(options2.keys())
# Identify changes
added = keys2 - keys1
removed = keys1 - keys2
common = keys1 & keys2
modified = []
deprecated_new = []
for key in common:
opt1 = options1[key]
opt2 = options2[key]
# Check if definition changed
if opt1['definition'] != opt2['definition']:
modified.append({
'option': key,
'old_definition': opt1['definition'],
'new_definition': opt2['definition']
})
# Check if newly deprecated
if 'deprecated' not in opt1['flags'] and 'deprecated' in opt2['flags']:
deprecated_new.append(key)
return {
'file': filename,
'added': sorted(added),
'removed': sorted(removed),
'modified': modified,
'deprecated_new': deprecated_new,
'options1_count': len(options1),
'options2_count': len(options2)
}
def compare_all(self) -> Dict:
"""Compare all grammar files between versions."""
# List of grammar files to compare
grammar_files = [
'options',
'forward.zoneopt',
'hint.zoneopt',
'in-view.zoneopt',
'mirror.zoneopt',
'primary.zoneopt',
'redirect.zoneopt',
'secondary.zoneopt',
'static-stub.zoneopt',
'stub.zoneopt',
'delegation-only.zoneopt',
'rndc.grammar',
]
results = {}
for filename in grammar_files:
result = self.compare_files(filename)
results[filename] = result
return results
def generate_markdown_report(self, results: Dict) -> str:
"""Generate a Markdown report from comparison results."""
lines = []
lines.append(f"# BIND9 Version Differences: {self.version1_name} vs {self.version2_name}")
lines.append("")
lines.append(f"This document compares BIND9 configuration grammar between {self.version1_name} and {self.version2_name}.")
lines.append("")
lines.append("Generated automatically by `scripts/compare_bind_versions.py`.")
lines.append("")
# Summary
lines.append("## Summary")
lines.append("")
total_added = sum(len(r['added']) for r in results.values())
total_removed = sum(len(r['removed']) for r in results.values())
total_modified = sum(len(r['modified']) for r in results.values())
total_deprecated = sum(len(r['deprecated_new']) for r in results.values())
lines.append(f"- **New Options**: {total_added}")
lines.append(f"- **Removed Options**: {total_removed} ⚠️")
lines.append(f"- **Modified Options**: {total_modified}")
lines.append(f"- **Newly Deprecated**: {total_deprecated}")
lines.append("")
# Breaking Changes
if total_removed > 0:
lines.append("## ⚠️ Breaking Changes")
lines.append("")
lines.append(f"The following options were removed in {self.version2_name} and will cause configuration errors:")
lines.append("")
for filename, result in results.items():
if result['removed']:
lines.append(f"### {filename}")
lines.append("")
for option in result['removed']:
lines.append(f"- `{option}`")
lines.append("")
# New Features
if total_added > 0:
lines.append("## ✨ New Features")
lines.append("")
lines.append(f"The following options were added in {self.version2_name}:")
lines.append("")
for filename, result in results.items():
if result['added']:
lines.append(f"### {filename}")
lines.append("")
for option in result['added']:
lines.append(f"- `{option}`")
lines.append("")
# Modified Options
if total_modified > 0:
lines.append("## 🔧 Modified Options")
lines.append("")
lines.append(f"The following options have syntax changes in {self.version2_name}:")
lines.append("")
for filename, result in results.items():
if result['modified']:
lines.append(f"### {filename}")
lines.append("")
for mod in result['modified']:
lines.append(f"#### `{mod['option']}`")
lines.append("")
lines.append(f"**{self.version1_name}**:")
lines.append(f"```")
lines.append(f"{mod['old_definition']}")
lines.append(f"```")
lines.append("")
lines.append(f"**{self.version2_name}**:")
lines.append(f"```")
lines.append(f"{mod['new_definition']}")
lines.append(f"```")
lines.append("")
# Deprecated Options
if total_deprecated > 0:
lines.append("## 📋 Newly Deprecated Options")
lines.append("")
lines.append(f"The following options were marked as deprecated in {self.version2_name}:")
lines.append("")
for filename, result in results.items():
if result['deprecated_new']:
lines.append(f"### {filename}")
lines.append("")
for option in result['deprecated_new']:
lines.append(f"- `{option}`")
lines.append("")
# File-by-File Comparison
lines.append("## Detailed File-by-File Comparison")
lines.append("")
for filename, result in results.items():
lines.append(f"### {filename}")
lines.append("")
lines.append(f"- {self.version1_name}: {result['options1_count']} options")
lines.append(f"- {self.version2_name}: {result['options2_count']} options")
lines.append(f"- Added: {len(result['added'])}")
lines.append(f"- Removed: {len(result['removed'])}")
lines.append(f"- Modified: {len(result['modified'])}")
lines.append("")
# Migration Guide
if total_removed > 0 or total_deprecated > 0:
lines.append("## Migration Guide")
lines.append("")
lines.append(f"### Migrating from {self.version1_name} to {self.version2_name}")
lines.append("")
if total_removed > 0:
lines.append("1. **Remove unsupported options** from your configuration")
lines.append(" - Review the Breaking Changes section above")
lines.append(" - Check if there are replacement options")
lines.append("")
if total_deprecated > 0:
lines.append("2. **Plan for deprecated options**")
lines.append(" - These options still work but may be removed in future versions")
lines.append(" - Start planning migration to recommended alternatives")
lines.append("")
lines.append("3. **Test your configuration**")
lines.append(" - Use `named-checkconf` to validate syntax")
lines.append(" - Test in a development environment before production")
lines.append("")
return '\n'.join(lines)
def main():
"""Main entry point."""
parser = argparse.ArgumentParser(
description="Compare BIND9 grammar files between versions"
)
parser.add_argument(
"--version1-dir",
type=Path,
required=True,
help="Directory containing first version's grammar files"
)
parser.add_argument(
"--version2-dir",
type=Path,
required=True,
help="Directory containing second version's grammar files"
)
parser.add_argument(
"--output",
type=Path,
default=Path("docs/BIND_VERSION_DIFFERENCES.md"),
help="Output file for Markdown report"
)
parser.add_argument(
"--json",
type=Path,
help="Also output raw comparison as JSON"
)
args = parser.parse_args()
# Validate directories
if not args.version1_dir.exists():
print(f"Error: {args.version1_dir} does not exist", file=sys.stderr)
sys.exit(1)
if not args.version2_dir.exists():
print(f"Error: {args.version2_dir} does not exist", file=sys.stderr)
sys.exit(1)
# Perform comparison
print(f"Comparing BIND9 versions:")
print(f" Version 1: {args.version1_dir.name}")
print(f" Version 2: {args.version2_dir.name}")
comparator = GrammarComparator(args.version1_dir, args.version2_dir)
results = comparator.compare_all()
# Generate and save Markdown report
report = comparator.generate_markdown_report(results)
args.output.parent.mkdir(parents=True, exist_ok=True)
with open(args.output, 'w', encoding='utf-8') as f:
f.write(report)
print(f"✓ Markdown report saved to: {args.output}")
# Save JSON if requested
if args.json:
args.json.parent.mkdir(parents=True, exist_ok=True)
with open(args.json, 'w', encoding='utf-8') as f:
json.dump(results, f, indent=2)
print(f"✓ JSON comparison saved to: {args.json}")
# Print summary
total_added = sum(len(r['added']) for r in results.values())
total_removed = sum(len(r['removed']) for r in results.values())
total_modified = sum(len(r['modified']) for r in results.values())
print(f"\nComparison Summary:")
print(f" Added options: {total_added}")
print(f" Removed options: {total_removed}")
print(f" Modified options: {total_modified}")
if total_removed > 0:
print(f"\n⚠️ Warning: {total_removed} breaking changes detected!")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,179 @@
#!/usr/bin/env python3
"""
Fetch BIND9 grammar files from Gitea mirror repository for version comparison.
This script uses the Gitea MCP tools to fetch grammar files from the official
BIND9 mirror at git.valid.dk/Mirrors/bind9 for specified version tags.
"""
import argparse
import json
import os
import sys
from pathlib import Path
from typing import Dict, List
# Grammar files to fetch from doc/misc/
GRAMMAR_FILES = [
"options",
"forward.zoneopt",
"hint.zoneopt",
"in-view.zoneopt",
"mirror.zoneopt",
"primary.zoneopt",
"redirect.zoneopt",
"secondary.zoneopt",
"static-stub.zoneopt",
"stub.zoneopt",
"delegation-only.zoneopt",
"rndc.grammar",
]
# Support files
SUPPORT_FILES = [
"parsegrammar.py",
"checkgrammar.py",
]
def fetch_file_content(owner: str, repo: str, ref: str, file_path: str) -> str:
"""
Fetch file content from Gitea repository.
This would use mcp_gitea-mcp_get_file_content in the actual MCP environment.
For standalone usage, returns placeholder.
"""
# In MCP environment, this would call:
# mcp_gitea-mcp_get_file_content(owner=owner, repo=repo, ref=ref, filePath=file_path)
print(f"Would fetch: {owner}/{repo}@{ref}:{file_path}")
return ""
def save_grammar_file(content: str, version: str, filename: str, output_dir: Path):
"""Save fetched grammar file to local directory."""
version_dir = output_dir / version / "grammar"
version_dir.mkdir(parents=True, exist_ok=True)
file_path = version_dir / filename
with open(file_path, 'w', encoding='utf-8') as f:
f.write(content)
print(f"Saved: {file_path}")
def fetch_version_grammars(owner: str, repo: str, tag: str, output_dir: Path):
"""Fetch all grammar files for a specific version tag."""
print(f"\n=== Fetching grammar files for {tag} ===")
# Create metadata
metadata = {
"version": tag,
"repository": f"{owner}/{repo}",
"files": [],
}
# Fetch grammar files
for grammar_file in GRAMMAR_FILES:
try:
file_path = f"doc/misc/{grammar_file}"
content = fetch_file_content(owner, repo, tag, file_path)
if content:
save_grammar_file(content, tag, grammar_file, output_dir)
metadata["files"].append({
"name": grammar_file,
"path": file_path,
"type": "grammar"
})
except Exception as e:
print(f"Warning: Could not fetch {grammar_file}: {e}")
# Fetch support files
for support_file in SUPPORT_FILES:
try:
file_path = f"doc/misc/{support_file}"
content = fetch_file_content(owner, repo, tag, file_path)
if content:
save_grammar_file(content, tag, support_file, output_dir)
metadata["files"].append({
"name": support_file,
"path": file_path,
"type": "support"
})
except Exception as e:
print(f"Warning: Could not fetch {support_file}: {e}")
# Save metadata
metadata_file = output_dir / tag / "metadata.json"
with open(metadata_file, 'w', encoding='utf-8') as f:
json.dump(metadata, f, indent=2)
print(f"Metadata saved: {metadata_file}")
return metadata
def main():
"""Main entry point."""
parser = argparse.ArgumentParser(
description="Fetch BIND9 grammar files from Gitea mirror"
)
parser.add_argument(
"--owner",
default="Mirrors",
help="Repository owner (default: Mirrors)"
)
parser.add_argument(
"--repo",
default="bind9",
help="Repository name (default: bind9)"
)
parser.add_argument(
"--tags",
nargs="+",
default=["v9.18.44", "v9.20.18"],
help="Version tags to fetch (default: v9.18.44 v9.20.18)"
)
parser.add_argument(
"--output-dir",
type=Path,
default=Path("bind9-grammar/upstream"),
help="Output directory for grammar files"
)
args = parser.parse_args()
print("BIND9 Grammar Fetcher")
print("=" * 60)
print(f"Repository: {args.owner}/{args.repo}")
print(f"Tags: {', '.join(args.tags)}")
print(f"Output: {args.output_dir}")
# Fetch grammars for each version
results = {}
for tag in args.tags:
try:
metadata = fetch_version_grammars(
args.owner,
args.repo,
tag,
args.output_dir
)
results[tag] = metadata
except Exception as e:
print(f"Error fetching {tag}: {e}")
sys.exit(1)
# Save overall summary
summary_file = args.output_dir / "fetch_summary.json"
with open(summary_file, 'w', encoding='utf-8') as f:
json.dump(results, f, indent=2)
print(f"\n=== Fetch complete ===")
print(f"Summary: {summary_file}")
print(f"Fetched {len(results)} versions")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,163 @@
#!/usr/bin/env python3
"""
Fetch BIND9 grammar files using Gitea MCP integration.
This script demonstrates how to use mcp_gitea-mcp tools to fetch grammar files.
Since we can't directly call MCP tools from Python, this serves as documentation
for the manual fetching process that should be done through the MCP interface.
Usage:
The actual fetching should be done through MCP tool calls:
1. List available tags:
mcp_gitea-mcp_list_tags(owner="Mirrors", repo="bind9")
2. Get directory listing:
mcp_gitea-mcp_get_dir_content(owner="Mirrors", repo="bind9",
ref="v9.18.44", filePath="doc/misc")
3. Fetch each grammar file:
mcp_gitea-mcp_get_file_content(owner="Mirrors", repo="bind9",
ref="v9.18.44",
filePath="doc/misc/options")
"""
import json
from pathlib import Path
from typing import Dict, List
# Target versions
VERSIONS = {
"9.18": "v9.18.44",
"9.20": "v9.20.18",
}
# Grammar files to fetch
GRAMMAR_FILES = [
"options",
"forward.zoneopt",
"hint.zoneopt",
"in-view.zoneopt",
"mirror.zoneopt",
"primary.zoneopt",
"redirect.zoneopt",
"secondary.zoneopt",
"static-stub.zoneopt",
"stub.zoneopt",
"delegation-only.zoneopt",
"rndc.grammar",
]
SUPPORT_FILES = [
"parsegrammar.py",
"checkgrammar.py",
]
def generate_fetch_commands() -> List[Dict]:
"""Generate MCP tool call commands for fetching grammar files."""
commands = []
for version_name, tag in VERSIONS.items():
# List directory command
commands.append({
"tool": "mcp_gitea-mcp_get_dir_content",
"params": {
"owner": "Mirrors",
"repo": "bind9",
"ref": tag,
"filePath": "doc/misc"
},
"description": f"List grammar files for {version_name} ({tag})"
})
# File fetch commands
for grammar_file in GRAMMAR_FILES + SUPPORT_FILES:
commands.append({
"tool": "mcp_gitea-mcp_get_file_content",
"params": {
"owner": "Mirrors",
"repo": "bind9",
"ref": tag,
"filePath": f"doc/misc/{grammar_file}"
},
"save_to": f"bind9-grammar/upstream/{tag}/grammar/{grammar_file}",
"description": f"Fetch {grammar_file} for {version_name}"
})
return commands
def save_file_structure() -> Dict:
"""Generate expected file structure after fetching."""
structure = {
"bind9-grammar": {
"upstream": {}
}
}
for version_name, tag in VERSIONS.items():
structure["bind9-grammar"]["upstream"][tag] = {
"grammar": {
"files": GRAMMAR_FILES + SUPPORT_FILES
},
"metadata.json": {
"version": tag,
"version_name": version_name,
"repository": "Mirrors/bind9",
"fetched_files": len(GRAMMAR_FILES) + len(SUPPORT_FILES)
}
}
return structure
def main():
"""Generate instructions and commands for grammar fetching."""
print("=" * 70)
print("BIND9 Grammar Fetcher - MCP Integration Guide")
print("=" * 70)
print("\nTarget Versions:")
for version_name, tag in VERSIONS.items():
print(f" - BIND {version_name}: {tag}")
print(f"\nFiles to fetch per version: {len(GRAMMAR_FILES)} grammar files + {len(SUPPORT_FILES)} support files")
print("\n" + "=" * 70)
print("MCP TOOL CALL SEQUENCE")
print("=" * 70)
commands = generate_fetch_commands()
for i, cmd in enumerate(commands, 1):
print(f"\n[{i}/{len(commands)}] {cmd['description']}")
print(f"Tool: {cmd['tool']}")
print(f"Parameters:")
for key, value in cmd['params'].items():
print(f" - {key}: {value}")
if 'save_to' in cmd:
print(f"Save to: {cmd['save_to']}")
print("\n" + "=" * 70)
print("EXPECTED FILE STRUCTURE")
print("=" * 70)
structure = save_file_structure()
print(json.dumps(structure, indent=2))
# Save command list
output_dir = Path("bind9-grammar/upstream")
output_dir.mkdir(parents=True, exist_ok=True)
commands_file = output_dir / "fetch_commands.json"
with open(commands_file, 'w') as f:
json.dump(commands, f, indent=2)
print(f"\nCommand list saved to: {commands_file}")
print("\nNote: These commands should be executed through the MCP interface,")
print(" not directly from this Python script.")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,78 @@
#!/usr/bin/env python3
"""
Fetch BIND9 grammar files using Gitea MCP tools.
This script must be run from an environment where MCP tools are available.
"""
import base64
import json
import sys
from pathlib import Path
# Files to fetch
GRAMMAR_FILES = [
"options",
"forward.zoneopt",
"hint.zoneopt",
"in-view.zoneopt",
"mirror.zoneopt",
"primary.zoneopt",
"redirect.zoneopt",
"secondary.zoneopt",
"static-stub.zoneopt",
"stub.zoneopt",
"delegation-only.zoneopt",
"rndc.grammar",
"parsegrammar.py",
"checkgrammar.py",
]
def save_file_from_mcp_result(result_json: dict, output_path: Path) -> bool:
"""Save a file from MCP tool result JSON."""
try:
if 'Result' in result_json and 'content' in result_json['Result']:
content_b64 = result_json['Result']['content']
content = base64.b64decode(content_b64).decode('utf-8')
output_path.parent.mkdir(parents=True, exist_ok=True)
with open(output_path, 'w', encoding='utf-8') as f:
f.write(content)
return True
return False
except Exception as e:
print(f"Error saving {output_path}: {e}", file=sys.stderr)
return False
def main():
"""Process stdin JSON from MCP tool calls."""
print("Reading MCP tool results from stdin...")
# Read all input
input_data = sys.stdin.read()
try:
result = json.loads(input_data)
# Determine output path from result metadata
if 'Result' in result and 'name' in result['Result']:
filename = result['Result']['name']
# Output path will be provided as command line argument
if len(sys.argv) > 1:
output_path = Path(sys.argv[1])
if save_file_from_mcp_result(result, output_path):
print(f"✓ Saved: {output_path}")
sys.exit(0)
else:
print(f"✗ Failed to save: {output_path}", file=sys.stderr)
sys.exit(1)
print("✗ Could not determine output path", file=sys.stderr)
sys.exit(1)
except json.JSONDecodeError as e:
print(f"✗ Invalid JSON input: {e}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,37 @@
#!/usr/bin/env python3
"""Helper script to save base64-encoded grammar file from MCP tool output."""
import base64
import json
import sys
from pathlib import Path
def main():
if len(sys.argv) != 3:
print("Usage: save_grammar_file.py <json_file> <output_path>")
sys.exit(1)
json_file = Path(sys.argv[1])
output_path = Path(sys.argv[2])
# Read JSON from MCP tool output
with open(json_file, 'r') as f:
data = json.load(f)
# Extract and decode base64 content
if 'Result' in data and 'content' in data['Result']:
content_b64 = data['Result']['content']
content = base64.b64decode(content_b64).decode('utf-8')
# Save to output path
output_path.parent.mkdir(parents=True, exist_ok=True)
with open(output_path, 'w', encoding='utf-8') as f:
f.write(content)
print(f"✓ Saved: {output_path}")
else:
print(f"✗ Error: No content found in JSON", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()

View File

@@ -15,10 +15,27 @@
state: directory state: directory
owner: root owner: root
group: root group: root
mode: 0750 mode: "0750"
when: bind9_backup_config is defined and bind9_backup_config | bool when: bind9_backup_config is defined and bind9_backup_config | bool
- name: Ensure logging directory exists if defined
ansible.builtin.file:
path: "{{ bind9_log_dir }}"
state: directory
owner: bind
group: bind
mode: "0750"
when:
- bind9_log_dir is defined
- bind9_log_dir is not none
- name: Deploy and Validate Configuration - name: Deploy and Validate Configuration
tags:
- bind9
- template
notify:
- Backup bind config
- Restart bind
block: block:
- name: Create backup of current config - name: Create backup of current config
ansible.builtin.copy: ansible.builtin.copy:
@@ -27,9 +44,10 @@
remote_src: true remote_src: true
owner: root owner: root
group: bind group: bind
mode: 0640 mode: "0640"
when: bind9_backup_config | bool
changed_when: false
failed_when: false # It's okay if the file doesn't exist yet failed_when: false # It's okay if the file doesn't exist yet
# We do this for every file in the loop
loop: "{{ bind9_config }}" loop: "{{ bind9_config }}"
loop_control: loop_control:
label: "{{ item.name }}" label: "{{ item.name }}"
@@ -40,11 +58,11 @@
dest: "{{ bind9_cfgdir }}/{{ item.name }}" dest: "{{ bind9_cfgdir }}/{{ item.name }}"
owner: root owner: root
group: bind group: bind
mode: 0640 mode: "0640"
loop: "{{ bind9_config }}" loop: "{{ bind9_config }}"
loop_control: loop_control:
label: "{{ item.name }}" label: "{{ item.name }}"
register: _template_result register: bind9_template_result
- name: Validate configuration using named-checkconf - name: Validate configuration using named-checkconf
ansible.builtin.command: ansible.builtin.command:
@@ -59,7 +77,7 @@
remote_src: true remote_src: true
owner: root owner: root
group: bind group: bind
mode: 0640 mode: "0640"
loop: "{{ bind9_config }}" loop: "{{ bind9_config }}"
loop_control: loop_control:
label: "{{ item.name }}" label: "{{ item.name }}"
@@ -67,7 +85,9 @@
- name: Fail due to invalid configuration - name: Fail due to invalid configuration
ansible.builtin.fail: ansible.builtin.fail:
msg: "Configuration validation failed. Changes have been reverted. Check the logs for named-checkconf errors." msg: |
Configuration validation failed. Changes have been reverted.
Check the logs for named-checkconf errors.
always: always:
- name: Remove backup files - name: Remove backup files
@@ -77,14 +97,7 @@
loop: "{{ bind9_config }}" loop: "{{ bind9_config }}"
loop_control: loop_control:
label: "{{ item.name }}" label: "{{ item.name }}"
when: bind9_backup_config | bool is false # Keep if backup is forced, otherwise cleanup temporary atomic backup when: bind9_backup_config | bool is false
tags:
- bind9
- template
notify:
- Backup bind config
- Restart bind
- name: Ensure the named service is started - name: Ensure the named service is started
ansible.builtin.service: ansible.builtin.service:

View File

@@ -111,3 +111,35 @@
{{ name }} "{{ value }}"; {{ name }} "{{ value }}";
{% endif %} {% endif %}
{% endmacro %} {% 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 %}

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 -}}

View File

@@ -2,4 +2,4 @@
- hosts: localhost - hosts: localhost
remote_user: root remote_user: root
roles: roles:
- bind9 - bind9 # noqa: syntax-check[specific]