tbm 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # Tunnels
2
+
3
+ A simple Ruby script to manage named SSH tunnels because I need these regularly and it's a bit of a pain to manage this in some other way.
4
+
5
+ At the moment, this will be a command that you invoke, and leave running. At some point, it might make sense to make this two processes -- one that stays alive while there are active tunnels, and a command-line that interacts with that process. For now, that's more work than I intend to bite off -- more of a v2 feature.
data/Rakefile ADDED
@@ -0,0 +1,42 @@
1
+ require 'rake/clean'
2
+ require 'rake/packagetask'
3
+ require 'rspec/core/rake_task'
4
+ require 'rspec'
5
+ require 'rubygems'
6
+ require 'rubygems/package_task'
7
+ require 'tbm'
8
+
9
+ CLEAN.include( 'coverage', 'pkg' )
10
+
11
+ desc '"spec" (run RSpec)'
12
+ task :default => :spec
13
+
14
+ desc "Run RSpec on spec/*"
15
+ RSpec::Core::RakeTask.new
16
+
17
+ desc "Generate code coverage"
18
+ RSpec::Core::RakeTask.new(:coverage) do |t|
19
+ t.rcov = true
20
+ t.rcov_opts = ['--exclude', 'spec,/gems/,/rubygems/', '--text-report']
21
+ end
22
+
23
+ spec = Gem::Specification.new do |spec|
24
+ spec.name = 'tbm'
25
+ spec.version = Tunnel::VERSION
26
+ spec.date = Tunnel::DATE
27
+ spec.summary = 'Named SSH tunnels, like bookmarks.'
28
+ spec.description = 'The "Tunnel Boring Machine" is meant to bore ssh tunnels through the internet to your desired destination simply and repeatedly, as often as you need them. This is a tool for someone who needs SSH tunnels frequently.'
29
+ spec.author = 'Geoffrey Wiseman'
30
+ spec.email = 'geoffrey.wiseman@codiform.com'
31
+ spec.homepage = 'http://github.com/geoffreywiseman/tunnel-boring-machine'
32
+ spec.executables << 'tbm'
33
+
34
+ spec.files = Dir['{lib,spec}/**/*.rb', 'bin/*', 'Rakefile', 'README.md', 'UNLICENSE']
35
+
36
+ spec.add_dependency( 'net/ssh', '>= 2.6.2' )
37
+ end
38
+
39
+ Gem::PackageTask.new( spec ) do |pkg|
40
+ pkg.need_tar_gz = true
41
+ pkg.need_zip = true
42
+ end
data/UNLICENSE ADDED
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <http://unlicense.org/>
data/bin/tbm ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'tbm'
4
+
5
+ Tunnel::CommandLineInterface.parse_and_run
data/lib/tbm.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'tunnel/meta'
2
+ require 'tunnel/cli'
3
+ require 'tunnel/config'
4
+ require 'tunnel/target'
data/lib/tunnel/cli.rb ADDED
@@ -0,0 +1,69 @@
1
+ require 'net/ssh'
2
+
3
+ module Tunnel
4
+ class CommandLineInterface
5
+ def initialize( config )
6
+ @config = config
7
+ @target = nil
8
+ @cancelled = false
9
+ end
10
+
11
+ def parse
12
+ if ARGV.size != 1
13
+ print_targets "SYNTAX: tbm <target>\n\nWhere target is one of:"
14
+ else
15
+ target_name = ARGV[0]
16
+ @target = @config.get_target( target_name )
17
+ print_targets( "Cannot find target: #{target_name}\n\nThese are the targets currently defined:" ) if @target.nil?
18
+ end
19
+ end
20
+
21
+ def print_targets( message )
22
+ puts message
23
+ @config.each_target { |target| puts "\t#{target.name}" }
24
+ end
25
+
26
+
27
+ def valid?
28
+ !@target.nil?
29
+ end
30
+
31
+ def bore
32
+ puts "Starting #{APP_NAME} v#{VERSION}"
33
+ puts
34
+
35
+ trap("INT") { @cancelled = true }
36
+ Net::SSH.start( @target.host, @target.username ) do |session|
37
+ forward_ports( session )
38
+ end
39
+
40
+ puts "Shutting down the machine."
41
+ end
42
+
43
+ def forward_ports( session )
44
+ begin
45
+ puts "Opened connection to #{@target.username}@#{@target.host}:"
46
+ @target.each_forward do |fwd|
47
+ remote_server, port = fwd
48
+ session.forward.local( port, remote_server, port )
49
+ puts "\tforwarded port #{port} to #{remote_server}:#{port}"
50
+ end
51
+ puts "\twaiting for Ctrl-C..."
52
+ session.loop(0.1) { not @cancelled }
53
+ puts "\n\tCtrl-C pressed. Exiting."
54
+ rescue Errno::EACCES
55
+ @cancelled = true
56
+ puts "\tCould not open all ports; you may need to sudo if port < 1000."
57
+ end
58
+ end
59
+
60
+ def self.parse_and_run
61
+ config = Config.new
62
+ if config.valid?
63
+ cli = CommandLineInterface.new( config )
64
+ cli.parse
65
+ cli.bore if cli.valid?
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,93 @@
1
+ require 'etc'
2
+
3
+ module Tunnel
4
+ class Config
5
+ CONFIG_FILE = File.expand_path( '~/.tunnels' )
6
+
7
+ def initialize
8
+ @valid = nil
9
+ @targets = []
10
+ if File.file? CONFIG_FILE
11
+ config_data = YAML.load_file( CONFIG_FILE )
12
+ parse config_data if config_data.is_a? Hash
13
+ else
14
+ puts "Configure your tunnels in ~/.tunnels in YAML form."
15
+ end
16
+ end
17
+
18
+ def valid?
19
+ @valid
20
+ end
21
+
22
+ def get_target( name )
23
+ @targets.find { |target| target.has_name?(name) }
24
+ end
25
+
26
+ def each_target( &block )
27
+ @targets.each { |target| yield target }
28
+ end
29
+
30
+ private
31
+
32
+ def parse( targets )
33
+ targets.each_key { |name| parse_target name, targets[name] }
34
+ @valid = true if @valid.nil? && !@targets.empty?
35
+ end
36
+
37
+ def parse_target( name, config )
38
+ if config.is_a? Hash
39
+ target = create_target( name, config )
40
+ unless target.nil?
41
+ @targets << target
42
+ parse_forward( target, config['forward'] )
43
+ end
44
+ else
45
+ puts "Cannot parse target '#{name}' (#{config.class})"
46
+ @valid = false
47
+ end
48
+ end
49
+
50
+ def create_target( name, config )
51
+ if config.has_key? 'host' then
52
+ if config.has_key? 'username' then
53
+ username = config['username']
54
+ else
55
+ username = Etc.getlogin
56
+ end
57
+ Target.new name, config['host'], username
58
+ else
59
+ puts "Cannot parse target '#{name}': no host found."
60
+ @valid = false
61
+ end
62
+ end
63
+
64
+ def parse_forward( target, config )
65
+ case config
66
+ when nil
67
+ puts "Target #{target.name} has no forwards defined."
68
+ @valid = false
69
+ when Fixnum
70
+ target.forward_port( config )
71
+ when Array
72
+ config.each { |port| target.forward_port(port) }
73
+ when Hash
74
+ config.each_key do |server|
75
+ server_config = config[ server ]
76
+ case server_config
77
+ when Fixnum
78
+ target.forward_port( server_config, server )
79
+ when Array
80
+ server_config.each { |port| target.forward_port( port, server ) }
81
+ else
82
+ puts "Not sure how to handle forward from #{target.host} to #{server}: #{server_config.class}"
83
+ end
84
+ end
85
+ else
86
+ puts "Not sure how to handle forward for '#{target.host}': #{config.class}"
87
+ @valid = false
88
+ end
89
+ end
90
+
91
+ end
92
+
93
+ end
@@ -0,0 +1,5 @@
1
+ module Tunnel
2
+ APP_NAME = "Tunnel Boring Machine"
3
+ VERSION = "0.1.0"
4
+ DATE = '2012-11-23'
5
+ end
@@ -0,0 +1,24 @@
1
+ module Tunnel
2
+ class Target
3
+ attr_reader :name, :host, :username
4
+
5
+ def initialize( name, host, username )
6
+ @name = name
7
+ @host = host
8
+ @username = username
9
+ @forwards = []
10
+ end
11
+
12
+ def forward_port( port, server='localhost' )
13
+ @forwards << [ server, port ]
14
+ end
15
+
16
+ def has_name?( name )
17
+ @name==name
18
+ end
19
+
20
+ def each_forward( &block )
21
+ @forwards.each { |fwd| yield fwd }
22
+ end
23
+ end
24
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tbm
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Geoffrey Wiseman
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2012-11-23 00:00:00 -05:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ type: :runtime
22
+ version_requirements: &id001 !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ segments:
27
+ - 2
28
+ - 6
29
+ - 2
30
+ version: 2.6.2
31
+ name: net/ssh
32
+ requirement: *id001
33
+ prerelease: false
34
+ description: The "Tunnel Boring Machine" is meant to bore ssh tunnels through the internet to your desired destination simply and repeatedly, as often as you need them. This is a tool for someone who needs SSH tunnels frequently.
35
+ email: geoffrey.wiseman@codiform.com
36
+ executables:
37
+ - tbm
38
+ extensions: []
39
+
40
+ extra_rdoc_files: []
41
+
42
+ files:
43
+ - lib/tbm.rb
44
+ - lib/tunnel/cli.rb
45
+ - lib/tunnel/config.rb
46
+ - lib/tunnel/meta.rb
47
+ - lib/tunnel/target.rb
48
+ - bin/tbm
49
+ - Rakefile
50
+ - README.md
51
+ - UNLICENSE
52
+ has_rdoc: true
53
+ homepage: http://github.com/geoffreywiseman/tunnel-boring-machine
54
+ licenses: []
55
+
56
+ post_install_message:
57
+ rdoc_options: []
58
+
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ segments:
66
+ - 0
67
+ version: "0"
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ requirements: []
76
+
77
+ rubyforge_project:
78
+ rubygems_version: 1.3.6
79
+ signing_key:
80
+ specification_version: 3
81
+ summary: Named SSH tunnels, like bookmarks.
82
+ test_files: []
83
+