net-ssh-socks 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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