diff --git a/.fixtures.yml b/.fixtures.yml
index 76c7fdb4..98776782 100644
--- a/.fixtures.yml
+++ b/.fixtures.yml
@@ -3,3 +3,4 @@ fixtures:
concat: "https://github.com/puppetlabs/puppetlabs-concat.git"
stdlib: "https://github.com/puppetlabs/puppetlabs-stdlib.git"
systemd: "https://github.com/voxpupuli/puppet-systemd.git"
+ extlib: "https://github.com/voxpupuli/puppet-extlib.git"
diff --git a/REFERENCE.md b/REFERENCE.md
index 6c5c78fc..62a1a3ac 100644
--- a/REFERENCE.md
+++ b/REFERENCE.md
@@ -20,6 +20,7 @@
### Functions
* [`unbound::print_config`](#unbound--print_config): Print a configuration value if it is defined and the version is supported
+* [`unbound::split_txt`](#unbound--split_txt): function to split TXT records. Long TXT records must be broken into strings of 255 characters as per RFC 4408
### Data types
@@ -2357,7 +2358,7 @@ Custom type Unbound::Local_zone_type.
##### `config_file`
-Data type: `Any`
+Data type: `Stdlib::Absolutepath`
name of configuration file.
@@ -2543,7 +2544,7 @@ Type: Puppet Language
Print a configuration value if it is defined and the version is supported
-#### `unbound::print_config(String[1] $name, Optional[Variant[Boolean, Integer, String, Array[String, 1]]] $value = undef, Optional[String[1]] $version = undef)`
+#### `unbound::print_config(String[1] $name, Optional[Variant[Boolean, Integer, String, Array[String]]] $value = undef, Optional[String[1]] $version = undef)`
The unbound::print_config function.
@@ -2557,7 +2558,7 @@ the config item name
##### `value`
-Data type: `Optional[Variant[Boolean, Integer, String, Array[String, 1]]]`
+Data type: `Optional[Variant[Boolean, Integer, String, Array[String]]]`
the config item value
@@ -2567,6 +2568,24 @@ Data type: `Optional[String[1]]`
the version when the config item was introduced
+### `unbound::split_txt`
+
+Type: Puppet Language
+
+function to split TXT records. Long TXT records must be broken into strings of 255 characters as per RFC 4408
+
+#### `unbound::split_txt(String[1] $data)`
+
+The unbound::split_txt function.
+
+Returns: `String[1]` A string of 255 character strings
+
+##### `data`
+
+Data type: `String[1]`
+
+A TXT record to split
+
## Data types
### `Unbound::Access_control`
diff --git a/functions/print_config.pp b/functions/print_config.pp
index c659143e..40be065d 100644
--- a/functions/print_config.pp
+++ b/functions/print_config.pp
@@ -5,13 +5,16 @@
# @return the config item as a string or an empty string if the version is not supported
function unbound::print_config (
String[1] $name,
- Optional[Variant[Boolean, Integer, String, Array[String, 1]]] $value = undef,
+ Optional[Variant[Boolean, Integer, String, Array[String]]] $value = undef,
Optional[String[1]] $version = undef,
) >> String {
$unbound_version = $facts['unbound_version'].lest || { '0.a' }
if ($value =~ Undef or ($version =~ NotUndef and versioncmp($unbound_version, $version) < 0)) {
return ''
}
+ if $value =~ Array and $value.empty {
+ return ''
+ }
$value ? {
String => " ${name}: \"${value}\"",
Integer => " ${name}: ${value}",
diff --git a/functions/split_txt.pp b/functions/split_txt.pp
new file mode 100644
index 00000000..60e61f2a
--- /dev/null
+++ b/functions/split_txt.pp
@@ -0,0 +1,8 @@
+# @summary function to split TXT records. Long TXT records must be broken into strings of 255 characters as per RFC 4408
+# @param data A TXT record to split
+# @return A string of 255 character strings
+function unbound::split_txt(
+ String[1] $data
+) >> String[1] {
+ $data.slice(255).map |$slice| { "\"${slice.join}\"" }.join
+}
diff --git a/manifests/dnstap.pp b/manifests/dnstap.pp
index 5ec6da77..44abea7b 100644
--- a/manifests/dnstap.pp
+++ b/manifests/dnstap.pp
@@ -98,7 +98,7 @@
concat::fragment { 'unbound-dnstap':
order => '20',
target => $unbound::config_file,
- content => $config.split("\n").filter |$x| { !$x.empty }.join("\n"),
+ content => $config.extlib::remove_blank_lines(),
}
}
}
diff --git a/manifests/forward.pp b/manifests/forward.pp
index f383bb05..8308101a 100644
--- a/manifests/forward.pp
+++ b/manifests/forward.pp
@@ -28,9 +28,18 @@
Pattern[/yes|no/] $forward_tls_upstream = 'no',
$config_file = $unbound::config_file,
) {
+ $content = @("CONTENT")
+ forward-zone:
+ ${unbound::print_config('name', $zone)}
+ ${unbound::print_config('forward-addr', $address)}
+ ${unbound::print_config('forward-host', $host)}
+ ${unbound::print_config('forward-first', $forward_first)}
+ ${unbound::print_config('forward-ssl-upstream', $forward_ssl_upstream)}
+ ${unbound::print_config('forward-tls-upstream', $forward_tls_upstream)}
+ | CONTENT
concat::fragment { "unbound-forward-${name}":
order => '20',
target => $config_file,
- content => template('unbound/forward.erb'),
+ content => $content.extlib::remove_blank_lines(),
}
}
diff --git a/manifests/localzone.pp b/manifests/localzone.pp
index 2f50cc89..ccfc16fb 100644
--- a/manifests/localzone.pp
+++ b/manifests/localzone.pp
@@ -26,15 +26,34 @@
# @param template_name Use a custom template.
#
define unbound::localzone (
- Unbound::Local_zone_type $type,
- String $zone = $name,
- $config_file = $unbound::config_file,
- Array[Unbound::Resource_record_type] $local_data = [],
- String $template_name = 'unbound/local_zone.erb'
+ Unbound::Local_zone_type $type,
+ String $zone = $name,
+ Stdlib::Absolutepath $config_file = $unbound::config_file,
+ String $template_name = 'unbound/local_zone.erb',
+ Array[Unbound::Resource_record_type] $local_data = [],
) {
+ # Loop through the local_data hash and create ablock of local-data strings with the correctly formated
+ # local-data lines which are ued in the final content block below.
+ # local-data: 'api.test.com 15 300 IN A 192.0.2.1
+ $records = $local_data.map |$record| {
+ $data = $record['data']
+ $_data = $record['type'] ? {
+ 'TXT' => $data.unbound::split_txt(),
+ default => $data,
+ }
+ $record_txt = "${record['name']} ${record['ttl']} ${record['class']} ${record['type']} ${_data}".regsubst(
+ /\s+/, ' ', 'G'
+ ) # Remove multiple spaces
+ " local-data: '${record_txt}'"
+ }.join("\n")
+ $content = @("CONTENT")
+ server:
+ local-zone: "${zone}" ${type}
+ ${records}
+ | CONTENT
concat::fragment { "unbound-localzone-${name}":
order => '06',
target => $config_file,
- content => template($template_name),
+ content => $content,
}
}
diff --git a/manifests/remote.pp b/manifests/remote.pp
index ed11a669..48f9dc73 100644
--- a/manifests/remote.pp
+++ b/manifests/remote.pp
@@ -50,10 +50,24 @@
$config_file = $unbound::config_file,
$control_setup_path = $unbound::control_setup_path,
) {
+ $_tls_config = @("CONFIG")
+ ${unbound::print_config('server-key-file', $server_key_file)}
+ ${unbound::print_config('server-cert-file', $server_cert_file)}
+ ${unbound::print_config('control-key-file', $control_key_file)}
+ ${unbound::print_config('control-cert-file', $control_cert_file)}
+ | CONFIG
+ $tls_config = $control_use_cert.bool2str($_tls_config, '')
+ $content = @("CONFIG")
+ remote-control:
+ ${unbound::print_config('control-enable', $enable)}
+ ${unbound::print_config('control-interface', $interface)}
+ ${unbound::print_config('control-port', $port)}
+ ${tls_config}
+ | CONFIG
concat::fragment { 'unbound-remote':
order => '10',
target => $config_file,
- content => template('unbound/remote.erb'),
+ content => $content.extlib::remove_blank_lines(),
}
unless $control_setup_path.empty {
diff --git a/manifests/stub.pp b/manifests/stub.pp
index bb619c29..735cd74a 100644
--- a/manifests/stub.pp
+++ b/manifests/stub.pp
@@ -20,7 +20,7 @@
# Controls 'stub-first' stub zone option.
# If true, a query that fails with the stub clause is attempted again
# without the stub clause.
-# @param type
+# @param type
# can be 'deny', 'refuse', 'static', 'transparent', 'typetransparent', 'redirect' or 'nodefault'.
# @param config_file Name of the unbound config file
#
@@ -37,10 +37,18 @@
) {
include unbound
$_config_file = pick($config_file, $unbound::config_file)
+ $content = @("CONFIG")
+ stub-zone:
+ ${unbound::print_config('name', $name)}
+ ${unbound::print_config('stub-addr', $address)}
+ ${unbound::print_config('stub-host', $nameservers)}
+ ${unbound::print_config('stub-first', $stub_first)}
+ ${unbound::print_config('stub-no-cache', $no_cache)}
+ | CONFIG
concat::fragment { "unbound-stub-${name}":
order => '15',
target => $_config_file,
- content => template('unbound/stub.erb'),
+ content => $content.extlib::remove_blank_lines(),
}
if str2bool($insecure) == true {
diff --git a/metadata.json b/metadata.json
index d92f131e..e14fe7f7 100644
--- a/metadata.json
+++ b/metadata.json
@@ -123,6 +123,10 @@
{
"name": "puppet/systemd",
"version_requirement": ">= 6.3.0 < 9.0.0"
+ },
+ {
+ "name": "puppet/extlib",
+ "version_requirement": ">= 7.4.0 < 8.0.0"
}
]
}
diff --git a/spec/classes/init_spec.rb b/spec/classes/init_spec.rb
index abd5d4b9..f47fe4ee 100644
--- a/spec/classes/init_spec.rb
+++ b/spec/classes/init_spec.rb
@@ -829,7 +829,14 @@
it do
expect(subject).to contain_concat__fragment('unbound-stub-example-stub.com').with_content(
- %r{^stub-zone:\n name: "example-stub.com"\n stub-addr: 10.0.0.1\n stub-addr: 10.0.0.2}
+ %r{
+ ^stub-zone:
+ \s+name:\s"example-stub.com"
+ \s+stub-addr:\s"10.0.0.1"
+ \s+stub-addr:\s"10.0.0.2"
+ \s+stub-first:\sno
+ \s+stub-no-cache:\sno
+ }x
)
end
end
@@ -843,7 +850,15 @@
it do
expect(subject).to contain_concat__fragment('unbound-forward-example-forward.com').with_content(
- %r{^forward-zone:\n name: "example-forward.com"\n forward-addr: 10.0.0.1\n forward-addr: 10.0.0.2\n forward-first: yes\n forward-ssl-upstream: yes}
+ %r{
+ ^forward-zone:
+ \s+name:\s"example-forward.com"
+ \s+forward-addr:\s"10.0.0.1"
+ \s+forward-addr:\s"10.0.0.2"
+ \s+forward-first:\s"yes"
+ \s+forward-ssl-upstream:\s"yes"
+ \s+forward-tls-upstream:\s"no"
+ }x
)
end
end
diff --git a/spec/classes/remote_spec.rb b/spec/classes/remote_spec.rb
index 8cbcbb34..0d9b03c8 100644
--- a/spec/classes/remote_spec.rb
+++ b/spec/classes/remote_spec.rb
@@ -29,13 +29,13 @@
%r{
^remote-control:
\s+control-enable:\sno
- \s+control-interface:\s::1
- \s+control-interface:\s127.0.0.1
+ \s+control-interface:\s"::1"
+ \s+control-interface:\s"127.0.0.1"
\s+control-port:\s8953
- \s+server-key-file:\s/etc/unbound/unbound_server.key
- \s+server-cert-file:\s/etc/unbound/unbound_server.pem
- \s+control-key-file:\s/etc/unbound/unbound_control.key
- \s+control-cert-file:\s/etc/unbound/unbound_control.pem
+ \s+server-key-file:\s"/etc/unbound/unbound_server.key"
+ \s+server-cert-file:\s"/etc/unbound/unbound_server.pem"
+ \s+control-key-file:\s"/etc/unbound/unbound_control.key"
+ \s+control-cert-file:\s"/etc/unbound/unbound_control.pem"
}x
)
end
@@ -62,7 +62,7 @@
it do
is_expected.to contain_concat__fragment('unbound-remote').with_content(
- %r{control-interface:\s192.0.2.42}
+ %r{control-interface:\s"192.0.2.42"}
)
end
end
diff --git a/spec/defines/stub_spec.rb b/spec/defines/stub_spec.rb
index 097b4022..aa54c3f4 100644
--- a/spec/defines/stub_spec.rb
+++ b/spec/defines/stub_spec.rb
@@ -20,11 +20,13 @@
it { is_expected.to contain_unbound__stub('lab.example.com') }
it {
- expect(subject).to contain_concat__fragment('unbound-stub-lab.example.com').with(
- content: <<~ZONE
+ expect(subject).to contain_concat__fragment('unbound-stub-lab.example.com').with_content(
+ <<~ZONE
stub-zone:
name: "lab.example.com"
- stub-addr: ::1
+ stub-addr: "::1"
+ stub-first: no
+ stub-no-cache: no
ZONE
)
}
@@ -42,13 +44,15 @@
it { is_expected.to contain_unbound__stub('lab.example.com') }
it {
- expect(subject).to contain_concat__fragment('unbound-stub-lab.example.com').with(
- content: <<~ZONE
+ expect(subject).to contain_concat__fragment('unbound-stub-lab.example.com').with_content(
+ <<~ZONE
stub-zone:
name: "lab.example.com"
- stub-addr: 10.0.0.10@10053
- stub-host: ns1.example.com
- stub-host: ns2.example.com
+ stub-addr: "10.0.0.10@10053"
+ stub-host: "ns1.example.com"
+ stub-host: "ns2.example.com"
+ stub-first: no
+ stub-no-cache: no
ZONE
)
}
@@ -66,11 +70,12 @@
it { is_expected.to contain_unbound__stub('lab.example.com') }
it {
- expect(subject).to contain_concat__fragment('unbound-stub-lab.example.com').with(
- content: <<~ZONE
+ expect(subject).to contain_concat__fragment('unbound-stub-lab.example.com').with_content(
+ <<~ZONE
stub-zone:
name: "lab.example.com"
- stub-addr: ::1
+ stub-addr: "::1"
+ stub-first: no
stub-no-cache: yes
ZONE
)
@@ -89,12 +94,13 @@
it { is_expected.to contain_unbound__stub('lab.example.com') }
it {
- expect(subject).to contain_concat__fragment('unbound-stub-lab.example.com').with(
- content: <<~ZONE
+ expect(subject).to contain_concat__fragment('unbound-stub-lab.example.com').with_content(
+ <<~ZONE
stub-zone:
name: "lab.example.com"
- stub-addr: ::1
+ stub-addr: "::1"
stub-first: yes
+ stub-no-cache: no
ZONE
)
}
@@ -112,11 +118,12 @@
it { is_expected.to contain_unbound__stub('lab.example.com') }
it {
- expect(subject).to contain_concat__fragment('unbound-stub-lab.example.com').with(
- content: <<~ZONE
+ expect(subject).to contain_concat__fragment('unbound-stub-lab.example.com').with_content(
+ <<~ZONE
stub-zone:
name: "lab.example.com"
- stub-addr: ::1
+ stub-addr: "::1"
+ stub-first: no
stub-no-cache: yes
ZONE
)
diff --git a/spec/functions/split_txt_spec.rb b/spec/functions/split_txt_spec.rb
new file mode 100644
index 00000000..a795058c
--- /dev/null
+++ b/spec/functions/split_txt_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+input = "Long TXT Record #{'X' * 255}"
+output = "\"Long TXT Record #{'X' * 239}\"\"#{'X' * 16}\""
+
+describe 'unbound::split_txt' do
+ it { is_expected.to run.with_params(input).and_return(output) }
+end
diff --git a/templates/forward.erb b/templates/forward.erb
deleted file mode 100644
index 9312ce74..00000000
--- a/templates/forward.erb
+++ /dev/null
@@ -1,17 +0,0 @@
-forward-zone:
- name: "<%= @zone %>"
-<% Array(@address).each do |addr| -%>
- forward-addr: <%= addr %>
-<% end -%>
-<% Array(@host).each do |h| -%>
- forward-host: <%= h %>
-<% end -%>
-<% if @forward_first != 'no' -%>
- forward-first: <%= @forward_first %>
-<% end -%>
-<% if @forward_ssl_upstream != 'no' -%>
- forward-ssl-upstream: <%= @forward_ssl_upstream %>
-<% end -%>
-<% if @forward_tls_upstream != 'no' -%>
- forward-tls-upstream: <%= @forward_tls_upstream %>
-<% end -%>
diff --git a/templates/local_zone.erb b/templates/local_zone.erb
deleted file mode 100644
index d4fd789f..00000000
--- a/templates/local_zone.erb
+++ /dev/null
@@ -1,15 +0,0 @@
-server:
- local-zone: "<%= @zone %>" <%= @type %>
- <%- @local_data.each do |resource_record| -%>
- <%- rr = resource_record['name'] -%>
- <%- rr = "#{rr} #{resource_record['ttl']}" if resource_record['ttl'] -%>
- <%- rr = "#{rr} #{resource_record['class']}" if resource_record['class'] -%>
- <%- rr = "#{rr} #{resource_record['type']}" -%>
- <%- if resource_record['type'] != 'TXT' -%>
- <%- rr = "#{rr} #{resource_record['data']}" -%>
- local-data: "<%= rr %>"
- <%- else -%>
- <%- rr = "#{rr} #{(resource_record['data'].scan /.{1,255}/).inject(''){|r, s| "#{r}\"#{s}\""}}" -%>
- local-data: '<%= rr %>'
- <%- end -%>
- <%- end -%>
diff --git a/templates/remote.erb b/templates/remote.erb
deleted file mode 100644
index 40b676ac..00000000
--- a/templates/remote.erb
+++ /dev/null
@@ -1,25 +0,0 @@
-remote-control:
-<% if @enable -%>
- control-enable: yes
-<% else -%>
- control-enable: no
-<% end -%>
-<% @interface.each do |int| -%>
- control-interface: <%= int %>
-<% end -%>
- control-port: <%= @port %>
-
-<% if @control_use_cert -%>
-<% if @server_key_file -%>
- server-key-file: <%= @server_key_file %>
-<% end -%>
-<% if @server_cert_file -%>
- server-cert-file: <%= @server_cert_file %>
-<% end -%>
-<% if @control_key_file -%>
- control-key-file: <%= @control_key_file %>
-<% end -%>
-<% if @control_cert_file -%>
- control-cert-file: <%= @control_cert_file %>
-<% end -%>
-<% end -%>
diff --git a/templates/stub.erb b/templates/stub.erb
deleted file mode 100644
index fbc9ccc2..00000000
--- a/templates/stub.erb
+++ /dev/null
@@ -1,14 +0,0 @@
-stub-zone:
- name: "<%= @name %>"
-<% [@address].flatten.each do |addr| -%>
- stub-addr: <%= addr %>
-<% end -%>
-<% @nameservers.each do |host| -%>
- stub-host: <%= host %>
-<% end -%>
-<% if @stub_first == 'true' or @stub_first == true -%>
- stub-first: yes
-<% end -%>
-<% if @no_cache == 'true' or @no_cache == true -%>
- stub-no-cache: yes
-<% end -%>