From 3481ef83efa3b0130d13fedcd3d191e7053a4e0e Mon Sep 17 00:00:00 2001 From: Thomas Bellman <bellman@nsc.liu.se> Date: Thu, 9 Feb 2023 21:02:26 +0100 Subject: [PATCH] Add 'trunc_to_net' flag to resolve_ipnets() function. This new flag will cause resolve_ipnets() to mask the resolved IP addresses with the specified netmask, thus "truncating" the address down to the network address for the subnet. For example, if the hostname "exempel.se" resolves to 2001:db8:17:23::69:3:4711, then "exempel.se/64" will return 2001:db8:17:23::/64, "exempel.se/112" will return 2001:db8:17:23::69:3:0/112, and "exempel.se/96" will yield the address 2001:db8:17:23:0:69::/96. This can be useful if you have an "example" host, and want to specify the entire subnet on which that host resides, but your application requires the address part of the CIDR specification given to it to be the network address, i.e. with all bits in the host part to be zero. --- lib/puppet/parser/functions/resolve_ipnets.rb | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/puppet/parser/functions/resolve_ipnets.rb b/lib/puppet/parser/functions/resolve_ipnets.rb index 61f408e..3405867 100644 --- a/lib/puppet/parser/functions/resolve_ipnets.rb +++ b/lib/puppet/parser/functions/resolve_ipnets.rb @@ -7,7 +7,8 @@ require 'ipaddr' module Puppet::Parser::Functions def resolve_ipnets__netspec( - addr, ipfamilies, on_error, do_partsort, forcemask) + addr, ipfamilies, on_error, do_partsort, forcemask, + truncate_to_network) familyname_sockaf_map = { :__ANY__ => Socket::AF_UNSPEC, # Internal use @@ -36,7 +37,7 @@ module Puppet::Parser::Functions end if m = /^\[(.*)\]$/.match(hostname) # "[" address "]" - if forcemask && maskspec == "" + if (forcemask && maskspec == "") || truncate_to_network raise(Puppet::ParseError, ("resolve_ipnets(): Can't force a netmask on bracketed" + " address, #{addr}")) @@ -71,6 +72,9 @@ module Puppet::Parser::Functions "Unsupported IP address, #{hostname}")) end end + if truncate_to_network && maskspec != "" + ip = ip.mask(maskspec[1..-1]) + end return [ip.to_s + maskspec] end end @@ -114,7 +118,12 @@ module Puppet::Parser::Functions else family_maskspec = maskspec end - ipaddrs += ips[family].collect {|ip| ip + family_maskspec } + ipaddrs += ips[family].collect { |ip| + if truncate_to_network && family_maskspec != "" + ip = IPAddr.new(ip + family_maskspec).to_s + end + ip + family_maskspec + } end if ipaddrs.length == 0 # Note: this will only show the last error message @@ -144,6 +153,12 @@ module Puppet::Parser::Functions Always add a host mask (/32 or /128) to the result if no mask was specified in the input. + "trunc_to_net" + Truncate the resolved address to the network address based + on the specified netmask. If e.g. "example.org" resolves + to 198.51.100.123, then "example.org/28" will result in + 198.51.100.112/28 with this flag in effect. + "ignoreerrors" If an address cannot be resolved, return it unchanged. @@ -215,6 +230,7 @@ module Puppet::Parser::Functions netspecs,*flags = args ipfamilies = [] forcemask = false + truncate_to_network = false on_error = :fail do_partsort = false # Sort addresses for each input netspec [flags].flatten.each do |f| @@ -223,6 +239,8 @@ module Puppet::Parser::Functions ipfamilies << f when 'forcemask' forcemask = true + when 'trunc_to_net' + truncate_to_network = true when 'ignoreerrors' on_error = :ignore when 'failerrors' @@ -239,7 +257,8 @@ module Puppet::Parser::Functions res = [] [netspecs].flatten.each do |netspec| res += Puppet::Parser::Functions::resolve_ipnets__netspec( - netspec, ipfamilies, on_error, do_partsort, forcemask) + netspec, ipfamilies, on_error, do_partsort, forcemask, + truncate_to_network) end return res.uniq end -- GitLab