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.
- data/README.md +12 -2
- data/lib/net/ssh/socks.rb +55 -13
- 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
|
data/lib/net/ssh/socks.rb
CHANGED
@@ -3,9 +3,8 @@ require 'net/ssh'
|
|
3
3
|
module Net
|
4
4
|
module SSH
|
5
5
|
class Socks
|
6
|
-
VERSION = "0.0.
|
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
|
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 = [
|
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 = ([
|
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
|
-
|
86
|
-
session.listen_to(
|
87
|
-
client =
|
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
|
-
|
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
|
-
|
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:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
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-
|
18
|
+
date: 2010-12-22 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|