diff --git a/bind/config.sls b/bind/config.sls index 1e8be69..4211fe5 100644 --- a/bind/config.sls +++ b/bind/config.sls @@ -1,4 +1,5 @@ {% from "bind/map.jinja" import map with context %} +{% from "bind/reverse_zone.jinja" import generate_reverse %} include: - bind @@ -175,6 +176,9 @@ bind_rndc_client_config: {% for zone, zone_data in view_data.get('configured_zones', {}).items() -%} {%- set file = salt['pillar.get']("bind:available_zones:" + zone + ":file", false) %} {%- set zone_records = salt['pillar.get']('bind:available_zones:' + zone + ':records', {}) %} +{%- if salt['pillar.get']('bind:available_zones:' + zone + ':generate_reverse') %} +{%- do generate_reverse(zone_records, salt['pillar.get']('bind:available_zones:' + zone + ':generate_reverse:net'), salt['pillar.get']('bind:available_zones:' + zone + ':generate_reverse:for_zones'), salt['pillar.get']('bind:available_zones', {})) %} +{%- endif %} {# If we define RRs in pillar, we use the internal template to generate the zone file otherwise, we fallback to the old behaviour and use the declared file #} diff --git a/bind/reverse_zone.jinja b/bind/reverse_zone.jinja new file mode 100644 index 0000000..085ad3c --- /dev/null +++ b/bind/reverse_zone.jinja @@ -0,0 +1,23 @@ +{%- macro generate_reverse(zone_records, net, for_zones, available_zones) %} +{%- set res = {} %} +{%- set net = salt['network.calc_net'](net) %} +{% set for_zones = [ for_zones ] if for_zones is string else for_zones %} +{%- for zone in for_zones %} +{%- set A_records = available_zones.get(zone, {}).get('records', {}).get('A', {}) %} +{%- for name, addr_list in A_records|dictsort %} +{%- set addr_list = [ addr_list ] if addr_list is string or addr_list is number else addr_list %} +{%- for addr in addr_list %} +{%- if salt['network.ip_in_subnet'](addr, net) %} +{%- if name.endswith('.') %} +{%- set full_name = name %} +{%- else %} +{%- set full_name = name + '.' + zone + '.' %} +{%- endif %} +{%- set rev_ip = '.'.join(addr.split('.')[::-1]) %} +{%- do res.update({rev_ip + '.in-addr.arpa.': full_name}) %} +{%- endif %} +{%- endfor %} +{%- endfor %} +{%- endfor %} +{%- do zone_records.update({'PTR': res }) %} +{%- endmacro %} diff --git a/pillar.example b/pillar.example index 7e47245..76eea68 100644 --- a/pillar.example +++ b/pillar.example @@ -302,6 +302,31 @@ bind: - '"v=spf1 mx a ip4:1.2.3.4 ~all"' _dmarc: '"v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com; fo=1:d:s; adkim=r; aspf=r; pct=100; ri=86400"' + + + + 3.2.1.in-addr.arpa: # auto-generated reverse zone + file: example.com.rev.txt + soa: # Declare the SOA RRs for the zone + ns: ns1.example.com # Required + contact: hostmaster.example.com # Required + serial: auto # autoupdate serial on each change + class: IN # Optional. Default: IN + refresh: 8600 # Optional. Default: 12h + retry: 900 # Optional. Default: 15m + expiry: 86000 # Optional. Default: 2w + nxdomain: 500 # Optional. Default: 1m + ttl: 8600 # Optional. Not set by default + records: # Records for the zone, grouped by type + NS: + '@': + ns1.example.com. + generate_reverse: # take all A records from example.com that are in 1.2.3.0/24 subnet + net: 1.2.3.0/24 # and generate reverse records for them + for_zones: + - example.com # example.com is a zone defined in pillar, see above + + ### Externally defined Zones ### bind: available_zones: