kerryb-net-ssh-socks 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in net-ssh-socks.gemspec
4
+ gemspec
@@ -0,0 +1,16 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ net-ssh-socks (0.0.2)
5
+ net-ssh (~> 2.0)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ net-ssh (2.1.4)
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ net-ssh-socks!
@@ -0,0 +1,28 @@
1
+ # Net::SSH::Socks
2
+
3
+ ## Description
4
+
5
+ Net::SSH::Socks is a library for programmatically creating a SOCKS proxy server that tunnels through SSH. Similar to Net::SSH::Service::Forward#local except the host is dynamic (determined by the client application, such as a browser).
6
+
7
+ Useful for securing traffic over SSH or getting in/out of a firewall.
8
+
9
+ ## Use cases
10
+
11
+ * If your company blocks certain sites/resources but allows SSH, then you can tunnel out to a machine outside the firewall.
12
+ * If you need to access sites/resources inside a firewall, then you can tunnel into a machine inside the firewall.
13
+ * Encrypt your traffic to protect yourself from things like Firesheep on public wifi.
14
+
15
+ ## Synopsis
16
+
17
+ require 'net/ssh/socks'
18
+
19
+ Net::SSH.start('host', 'user') do |ssh|
20
+ ssh.forward.socks(8080)
21
+ ssh.loop { true }
22
+ end
23
+
24
+ Now, configure your browser to use a SOCKS proxy at localhost:8080
25
+
26
+ ## Install
27
+
28
+ gem install net-ssh-socks
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,146 @@
1
+ require 'net/ssh'
2
+
3
+ module Net
4
+ module SSH
5
+ class Socks
6
+ VERSION = "0.0.3"
7
+
8
+ METHOD_NO_AUTH = 0
9
+ CMD_CONNECT = 1
10
+ REP_SUCCESS = 0
11
+ RESERVED = 0
12
+ ATYP_IPV4 = 1
13
+ ATYP_DOMAIN = 3
14
+ ATYP_IPV6 = 4
15
+ SOCKS4 = 4
16
+ SOCKS4_SUCCESS = [0, 0x5a, 0, 0, 0, 0, 0, 0].pack("C*")
17
+ SOCKS5 = 5
18
+
19
+ # client is an open socket
20
+ def initialize(client)
21
+ @client = client
22
+ end
23
+
24
+ # Communicates with a client application as described by the SOCKS 5
25
+ # specification: http://tools.ietf.org/html/rfc1928 and
26
+ # http://en.wikipedia.org/wiki/SOCKS
27
+ # returns the host and port requested by the client
28
+ def client_handshake
29
+ version = @client.recv(1).unpack("C*").first
30
+ case version
31
+ when SOCKS4 then client_handshake_v4
32
+ when SOCKS5 then client_handshake_v5
33
+ else
34
+ raise "SOCKS version not supported: #{version.inspect}"
35
+ end
36
+ end
37
+
38
+ def client_handshake_v4
39
+ command = @client.recv(1)
40
+ port = @client.recv(2).unpack("n").first
41
+ ip_addr = @client.recv(4).unpack("C*").join('.')
42
+ username = @client.recv(1024) # read the rest of the stream
43
+
44
+ @client.send SOCKS4_SUCCESS, 0
45
+ [ip_addr, port]
46
+ end
47
+
48
+ def client_handshake_v5
49
+ nmethods, *methods = @client.recv(8).unpack("C*")
50
+
51
+ if methods.include?(METHOD_NO_AUTH)
52
+ packet = [SOCKS5, METHOD_NO_AUTH].pack("C*")
53
+ @client.send packet, 0
54
+ else
55
+ @client.close
56
+ raise 'Unsupported authentication method. Only "No Authentication" is supported'
57
+ end
58
+
59
+ version, command, reserved, address_type, *destination = @client.recv(256).unpack("C*")
60
+
61
+ packet = ([SOCKS5, REP_SUCCESS, RESERVED, address_type] + destination).pack("C*")
62
+ @client.send packet, 0
63
+
64
+ remote_host, remote_port = case address_type
65
+ when ATYP_IPV4
66
+ host = destination[0..-3].join('.')
67
+ port = destination[-2..-1].pack('C*').unpack('n')
68
+ [host, port]
69
+ when ATYP_DOMAIN
70
+ host = destination[1..-3].pack('C*')
71
+ port = destination[-2..-1].pack('C*').unpack('n')
72
+ [host, port]
73
+ when ATYP_IPV6
74
+ @client.close
75
+ raise 'Unsupported address type. Only "IPv4" is supported'
76
+ else
77
+ raise "Unknown address_type: #{address_type}"
78
+ end
79
+
80
+ [remote_host, remote_port]
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ class Net::SSH::Connection::Session
87
+ def on_close(&block)
88
+ @on_close = block
89
+ end
90
+
91
+ alias_method :close_without_callbacks, :close
92
+ def close
93
+ close_without_callbacks
94
+ @on_close.call if @on_close
95
+ end
96
+ end
97
+
98
+ class Net::SSH::Service::Forward
99
+ # Starts listening for connections on the local host, and forwards them
100
+ # to the specified remote host/port via the SSH connection. This method
101
+ # accepts either one or two arguments. When two arguments are given,
102
+ # they are:
103
+ #
104
+ # * the local address to bind to
105
+ # * the local port to listen on
106
+ #
107
+ # If one argument is given, it is as if the local bind address is
108
+ # "127.0.0.1", and the rest are applied as above.
109
+ #
110
+ # ssh.forward.socks(8080)
111
+ # ssh.forward.socks("0.0.0.0", 8080)
112
+ def socks(*args)
113
+ if args.length < 1 || args.length > 2
114
+ raise ArgumentError, "expected 1 or 2 parameters, got #{args.length}"
115
+ end
116
+
117
+ bind_address = "127.0.0.1"
118
+ bind_address = args.shift if args.first.is_a?(String) && args.first =~ /\D/
119
+ local_port = args.shift.to_i
120
+ info { "socks on #{bind_address} port #{local_port}" }
121
+
122
+ socks_server = TCPServer.new(bind_address, local_port)
123
+ session.listen_to(socks_server) do |server|
124
+ client = server.accept
125
+
126
+ socks = Net::SSH::Socks.new(client)
127
+ remote_host, remote_port = socks.client_handshake
128
+ info { "connection requested on #{remote_host} port #{remote_port}" }
129
+
130
+ channel = session.open_channel("direct-tcpip", :string, remote_host, :long, remote_port, :string, bind_address, :long, local_port) do |channel|
131
+ info { "direct channel established" }
132
+ prepare_client(client, channel, :local)
133
+ end
134
+
135
+ channel.on_open_failed do |ch, code, description|
136
+ error { "could not establish direct channel: #{description} (#{code})" }
137
+ client.close
138
+ end
139
+ end
140
+
141
+ session.on_close do
142
+ debug { "cleaning up socks server" }
143
+ socks_server.close
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require 'net/ssh/socks'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "kerryb-net-ssh-socks"
7
+ s.version = Net::SSH::Socks::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Mike Enriquez"]
10
+ s.email = ["mike@edgecase.com"]
11
+ s.homepage = ""
12
+ s.summary = %q{An extension to Net::SSH that adds dynamic port forwarding through a SOCKS proxy}
13
+ s.description = %q{Net::SSH::Socks is a library for programmatically creating a SOCKS proxy. Similar to Net::SSH::Service::Forward#local except the host is dynamic (determined by the client application, such as a browser).}
14
+
15
+ s.rubyforge_project = "net-ssh-socks"
16
+
17
+ s.add_dependency "net-ssh", "~> 2.0"
18
+
19
+ s.files = `git ls-files`.split("\n")
20
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
+ s.require_paths = ["lib"]
23
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kerryb-net-ssh-socks
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.3
6
+ platform: ruby
7
+ authors:
8
+ - Mike Enriquez
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-05-02 00:00:00 +01:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: net-ssh
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: "2.0"
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ description: Net::SSH::Socks is a library for programmatically creating a SOCKS proxy. Similar to Net::SSH::Service::Forward#local except the host is dynamic (determined by the client application, such as a browser).
28
+ email:
29
+ - mike@edgecase.com
30
+ executables: []
31
+
32
+ extensions: []
33
+
34
+ extra_rdoc_files: []
35
+
36
+ files:
37
+ - .gitignore
38
+ - Gemfile
39
+ - Gemfile.lock
40
+ - README.md
41
+ - Rakefile
42
+ - lib/net/ssh/socks.rb
43
+ - net-ssh-socks.gemspec
44
+ has_rdoc: true
45
+ homepage: ""
46
+ licenses: []
47
+
48
+ post_install_message:
49
+ rdoc_options: []
50
+
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ requirements: []
66
+
67
+ rubyforge_project: net-ssh-socks
68
+ rubygems_version: 1.6.2
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: An extension to Net::SSH that adds dynamic port forwarding through a SOCKS proxy
72
+ test_files: []
73
+