diff --git a/provider_base/lib/macros/secrets.rb b/provider_base/lib/macros/secrets.rb index 8d1feb55..9965d72f 100644 --- a/provider_base/lib/macros/secrets.rb +++ b/provider_base/lib/macros/secrets.rb @@ -21,9 +21,15 @@ def base32_secret(name, length=20) manager.secrets.set(name, @node.environment) { Base32.encode(Util::Secret.generate(length)) } end - # Picks a random obfsproxy port from given range - def rand_range(name, range) - manager.secrets.set(name, @node.environment) { rand(range) } + # Picks a random number in the given range, ensuring it is unique over keys that + # match the specified regexp. + def rand_range(name, range, unique_regexp=nil) + manager.secrets.set(name, @node.environment) do + begin + value = rand(range) + end until (unique_regexp.nil? || !manager.secrets.taken?(unique_regexp, value, @node.environment)) + value + end end # diff --git a/provider_base/lib/macros/stunnel.rb b/provider_base/lib/macros/stunnel.rb index f16308c7..5c4bc469 100644 --- a/provider_base/lib/macros/stunnel.rb +++ b/provider_base/lib/macros/stunnel.rb @@ -82,14 +82,16 @@ def stunnel_server(port) # maps a real port to a stunnel port (used as the connect_port in the client config # and the accept_port in the server config) # - def stunnel_port(port) - port = port.to_i - if port < 50000 - return port + 10000 + # generates a port in the range 10000 -> 20000. + # + def stunnel_port(real_port) + if manager.secrets.respond_to?(:taken?) + # if secrets library supports it, use a truly random, non-colliding port + rand_range("stunnel_map_port_#{real_port}_to", 10000..20000, /^stunnel_map_port_/) else - return port - 10000 + (real_port.to_i % 20000) + 10000 end end end -end \ No newline at end of file +end