summaryrefslogtreecommitdiff
path: root/lib/leap_cli/macros/stunnel.rb
blob: 821bda38ce744068678e17e928a92c852768a9b2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
##
## STUNNEL
##

#
# About stunnel
# --------------------------
#
# The network looks like this:
#
#   From the client's perspective:
#
#   |------- stunnel client --------------|    |---------- stunnel server -----------------------|
#    consumer app -> localhost:accept_port  ->  connect:connect_port -> ??
#
#   From the server's perspective:
#
#   |------- stunnel client --------------|    |---------- stunnel server -----------------------|
#                                       ??  ->  *:accept_port -> localhost:connect_port -> service
#

module LeapCli
  module Macro

    #
    # stunnel configuration for the client side.
    #
    # +node_list+ is a ObjectList of nodes running stunnel servers.
    #
    # +port+ is the real port of the ultimate service running on the servers
    # that the client wants to connect to.
    #
    # * accept_port is the port on localhost to which local clients
    #   can connect. it is auto generated serially.
    #
    # * connect_port is the port on the stunnel server to connect to.
    #   it is auto generated from the +port+ argument.
    #
    # generates an entry appropriate to be passed directly to
    # create_resources(stunnel::service, hiera('..'), defaults)
    #
    # local ports are automatically generated, starting at 4000
    # and incrementing in sorted order (by node name).
    #
    def stunnel_client(node_list, port, options={})
      @next_stunnel_port ||= 4000
      node_list = listify(node_list)
      hostnames(node_list) # record the hosts
      result = Config::ObjectList.new
      node_list.each_node do |node|
        if node.name != self.name || options[:include_self]
          s_port = stunnel_port(port)
          result["#{node.name}_#{port}"] = Config::Object[
            'accept_port', @next_stunnel_port,
            'connect', node.domain.internal,
            'connect_port', s_port,
            'original_port', port
          ]
          manager.connections.add(:from => @node.ip_address, :to => node.ip_address, :port => s_port)
          @next_stunnel_port += 1
        end
      end
      result
    end

    #
    # generates a stunnel server entry.
    #
    # +port+ is the real port targeted service.
    #
    # * `accept_port` is the publicly bound port
    # * `connect_port` is the port that the local service is running on.
    #
    def stunnel_server(port)
      {
        "accept_port" => stunnel_port(port),
        "connect_port" => port
      }
    end

    #
    # lists the ips that connect to this node, on particular ports.
    #
    def stunnel_firewall
      manager.connections.select {|connection|
        connection['to'] == @node.ip_address
      }
    end

    private

    #
    # 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
      else
        return port - 10000
      end
    end

  end
end