net-ssh-socks 0.0.1 → 0.0.2

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.
Files changed (3) hide show
  1. data/README.md +12 -2
  2. data/lib/net/ssh/socks.rb +55 -13
  3. metadata +4 -4
data/README.md CHANGED
@@ -2,17 +2,27 @@
2
2
 
3
3
  ## Description
4
4
 
5
- Net::SSH::Socks is a library for programmatically creating a SOCKS proxy 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).
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.
6
14
 
7
15
  ## Synopsis
8
16
 
9
- require 'net/ssh'
10
17
  require 'net/ssh/socks'
11
18
 
12
19
  Net::SSH.start('host', 'user') do |ssh|
13
20
  ssh.forward.socks(8080)
21
+ ssh.loop { true }
14
22
  end
15
23
 
24
+ Now, configure your browser to use a SOCKS proxy at localhost:8080
25
+
16
26
  ## Install
17
27
 
18
28
  gem install net-ssh-socks
@@ -3,9 +3,8 @@ require 'net/ssh'
3
3
  module Net
4
4
  module SSH
5
5
  class Socks
6
- VERSION = "0.0.1"
6
+ VERSION = "0.0.2"
7
7
 
8
- SOCKS_VERSION = 5
9
8
  METHOD_NO_AUTH = 0
10
9
  CMD_CONNECT = 1
11
10
  REP_SUCCESS = 0
@@ -13,6 +12,9 @@ module Net
13
12
  ATYP_IPV4 = 1
14
13
  ATYP_DOMAIN = 3
15
14
  ATYP_IPV6 = 4
15
+ SOCKS4 = 4
16
+ SOCKS4_SUCCESS = [0, 0x5a, 0, 0, 0, 0, 0, 0].pack("C*")
17
+ SOCKS5 = 5
16
18
 
17
19
  # client is an open socket
18
20
  def initialize(client)
@@ -20,14 +22,34 @@ module Net
20
22
  end
21
23
 
22
24
  # Communicates with a client application as described by the SOCKS 5
23
- # specification: http://tools.ietf.org/html/rfc1928.
24
- #
25
+ # specification: http://tools.ietf.org/html/rfc1928 and
26
+ # http://en.wikipedia.org/wiki/SOCKS
25
27
  # returns the host and port requested by the client
26
28
  def client_handshake
27
- version, nmethods, *methods = @client.recv(8).unpack("C*")
29
+ version = @client.recv(1).unpack("C*").first
30
+ case version
31
+ when SOCKS4 : client_handshake_v4
32
+ when SOCKS5 : 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*")
28
50
 
29
51
  if methods.include?(METHOD_NO_AUTH)
30
- packet = [SOCKS_VERSION, METHOD_NO_AUTH].pack("C*")
52
+ packet = [SOCKS5, METHOD_NO_AUTH].pack("C*")
31
53
  @client.send packet, 0
32
54
  else
33
55
  @client.close
@@ -36,7 +58,7 @@ module Net
36
58
 
37
59
  version, command, reserved, address_type, *destination = @client.recv(256).unpack("C*")
38
60
 
39
- packet = ([SOCKS_VERSION, REP_SUCCESS, RESERVED, address_type] + destination).pack("C*")
61
+ packet = ([SOCKS5, REP_SUCCESS, RESERVED, address_type] + destination).pack("C*")
40
62
  @client.send packet, 0
41
63
 
42
64
  remote_host, remote_port = case address_type
@@ -50,15 +72,28 @@ module Net
50
72
  when ATYP_IPV6
51
73
  @client.close
52
74
  raise 'Unsupported address type. Only "IPv4" is supported'
75
+ else
76
+ raise "Unknown address_type: #{address_type}"
53
77
  end
54
78
 
55
79
  [remote_host, remote_port]
56
80
  end
57
-
58
81
  end
59
82
  end
60
83
  end
61
84
 
85
+ class Net::SSH::Connection::Session
86
+ def on_close(&block)
87
+ @on_close = block
88
+ end
89
+
90
+ alias_method :close_without_callbacks, :close
91
+ def close
92
+ close_without_callbacks
93
+ @on_close.call if @on_close
94
+ end
95
+ end
96
+
62
97
  class Net::SSH::Service::Forward
63
98
  # Starts listening for connections on the local host, and forwards them
64
99
  # to the specified remote host/port via the SSH connection. This method
@@ -81,23 +116,30 @@ class Net::SSH::Service::Forward
81
116
  bind_address = "127.0.0.1"
82
117
  bind_address = args.shift if args.first.is_a?(String) && args.first =~ /\D/
83
118
  local_port = args.shift.to_i
119
+ info { "socks on #{bind_address} port #{local_port}" }
84
120
 
85
- socket = TCPServer.new(bind_address, local_port)
86
- session.listen_to(socket) do |socket|
87
- client = socket.accept
121
+ socks_server = TCPServer.new(bind_address, local_port)
122
+ session.listen_to(socks_server) do |server|
123
+ client = server.accept
88
124
 
89
125
  socks = Net::SSH::Socks.new(client)
90
126
  remote_host, remote_port = socks.client_handshake
127
+ info { "connection requested on #{remote_host} port #{remote_port}" }
91
128
 
92
129
  channel = session.open_channel("direct-tcpip", :string, remote_host, :long, remote_port, :string, bind_address, :long, local_port) do |channel|
93
- channel.info { "direct channel established" }
130
+ info { "direct channel established" }
94
131
  prepare_client(client, channel, :local)
95
132
  end
96
133
 
97
134
  channel.on_open_failed do |ch, code, description|
98
- channel.error { "could not establish direct channel: #{description} (#{code})" }
135
+ error { "could not establish direct channel: #{description} (#{code})" }
99
136
  client.close
100
137
  end
101
138
  end
139
+
140
+ session.on_close do
141
+ debug { "cleaning up socks server" }
142
+ socks_server.close
143
+ end
102
144
  end
103
145
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: net-ssh-socks
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 1
10
- version: 0.0.1
9
+ - 2
10
+ version: 0.0.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Mike Enriquez
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-11-21 00:00:00 -05:00
18
+ date: 2010-12-22 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency