sockit 0.0.4 → 1.0.0
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.
- checksums.yaml +7 -0
- data/.rspec +1 -1
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +12 -10
- data/.yardopts +2 -0
- data/README.md +25 -16
- data/bin/sockit +3 -2
- data/lib/sockit/connection.rb +43 -0
- data/lib/sockit/support.rb +53 -0
- data/lib/sockit/v4/connection.rb +62 -0
- data/lib/sockit/v4/support.rb +31 -0
- data/lib/sockit/v5/authentication.rb +105 -0
- data/lib/sockit/v5/connection.rb +98 -0
- data/lib/sockit/v5/support.rb +82 -0
- data/lib/sockit/version.rb +5 -1
- data/lib/sockit.rb +46 -316
- data/sockit.gemspec +26 -16
- data/spec/sockit/sockit_spec.rb +211 -0
- data/spec/spec_helper.rb +43 -0
- data/spec/support/before_install.sh +33 -0
- data/spec/support/ss5-3.8.9-8.tar.gz +0 -0
- metadata +127 -37
- data/.rvmrc.template +0 -1
- data/bin/setup-travis-ci.sh +0 -11
data/lib/sockit.rb
CHANGED
@@ -18,348 +18,78 @@
|
|
18
18
|
#
|
19
19
|
################################################################################
|
20
20
|
|
21
|
-
require
|
22
|
-
require
|
21
|
+
require 'socket'
|
22
|
+
require 'resolv'
|
23
|
+
require 'ostruct'
|
23
24
|
|
24
|
-
require
|
25
|
+
require 'sockit/version'
|
26
|
+
|
27
|
+
require 'sockit/v4/connection'
|
28
|
+
require 'sockit/v4/support'
|
29
|
+
|
30
|
+
require 'sockit/v5/authentication'
|
31
|
+
require 'sockit/v5/connection'
|
32
|
+
require 'sockit/v5/support'
|
33
|
+
|
34
|
+
require 'sockit/connection'
|
35
|
+
require 'sockit/support'
|
25
36
|
|
26
37
|
class SockitError < RuntimeError; end
|
27
38
|
|
28
39
|
module Sockit
|
29
40
|
DEFAULT_CONFIG = {
|
30
41
|
:version => 5,
|
31
|
-
:ignore
|
32
|
-
:debug
|
42
|
+
:ignore => %w( 127.0.0.1 ),
|
43
|
+
:debug => false
|
33
44
|
}
|
34
45
|
|
35
46
|
COLORS = {
|
36
|
-
:reset
|
37
|
-
:red
|
38
|
-
:green
|
39
|
-
:yellow => "\e[1m\e[33m"
|
47
|
+
:reset => "\e[0m\e[37m",
|
48
|
+
:red => "\e[1m\e[31m",
|
49
|
+
:green => "\e[1m\e[32m",
|
50
|
+
:yellow => "\e[1m\e[33m",
|
51
|
+
:blue => "\e[1m\e[34m"
|
40
52
|
}
|
41
53
|
|
42
|
-
|
43
|
-
|
44
|
-
def debug(color, message)
|
45
|
-
timestamp = Time.now.utc
|
46
|
-
puts("%s%s.%06d %s%s" % [COLORS[color], timestamp.strftime("%Y-%m-%d|%H:%M:%S"), timestamp.usec, message, COLORS[:reset]])
|
47
|
-
end
|
48
|
-
|
49
|
-
def dump(action, data)
|
50
|
-
bytes = Array.new
|
51
|
-
chars = Array.new
|
52
|
-
for x in 0..(data.length - 1) do
|
53
|
-
bytes << ("%03d" % data[x].ord)
|
54
|
-
chars << ("%03s" % (data[x] =~ /^\w+$/ ? data[x].chr : "..."))
|
55
|
-
end
|
56
|
-
debug(:red, "#{action.to_s.upcase}: #{bytes.join(" ")}#{COLORS[:reset]}")
|
57
|
-
debug(:red, "#{action.to_s.upcase}: #{chars.join(" ")}#{COLORS[:reset]}")
|
58
|
-
end
|
59
|
-
|
60
|
-
# 0x00 = request granted
|
61
|
-
# 0x01 = general failure
|
62
|
-
# 0x02 = connection not allowed by ruleset
|
63
|
-
# 0x03 = network unreachable
|
64
|
-
# 0x04 = host unreachable
|
65
|
-
# 0x05 = connection refused by destination host
|
66
|
-
# 0x06 = TTL expired
|
67
|
-
# 0x07 = command not supported / protocol error
|
68
|
-
# 0x08 = address type not supported
|
69
|
-
def status_message(status_code)
|
70
|
-
case status_code
|
71
|
-
when 0x00 then
|
72
|
-
"Request granted (Code: 0x%02X)" % status_code
|
73
|
-
when 0x01 then
|
74
|
-
"General failure (Code: 0x%02X)" % status_code
|
75
|
-
when 0x02 then
|
76
|
-
"Connection not allowed by ruleset (Code: 0x%02X)" % status_code
|
77
|
-
when 0x03 then
|
78
|
-
"Network unreachable (Code: 0x%02X)" % status_code
|
79
|
-
when 0x04 then
|
80
|
-
"Host unreachable (Code: 0x%02X)" % status_code
|
81
|
-
when 0x05 then
|
82
|
-
"Connection refused by destination host (Code: 0x%02X)" % status_code
|
83
|
-
when 0x06 then
|
84
|
-
"TTL expired (Code: 0x%02X)" % status_code
|
85
|
-
when 0x07 then
|
86
|
-
"Command not supported / Protocol error (Code: 0x%02X)" % status_code
|
87
|
-
when 0x08 then
|
88
|
-
"Address type not supported (Code: 0x%02X)" % status_code
|
89
|
-
else
|
90
|
-
"Unknown (Code: 0x%02X)" % status_code
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
# The authentication methods supported are numbered as follows:
|
95
|
-
# 0x00: No authentication
|
96
|
-
# 0x01: GSSAPI[10]
|
97
|
-
# 0x02: Username/Password[11]
|
98
|
-
# 0x03-0x7F: methods assigned by IANA[12]
|
99
|
-
# 0x80-0xFE: methods reserved for private use
|
100
|
-
def authentication_method(auth_method)
|
101
|
-
case auth_method
|
102
|
-
when 0x00 then
|
103
|
-
"No authentication (Code: 0x%02X)" % auth_method
|
104
|
-
when 0x01 then
|
105
|
-
"GSSAPI authentication (Code: 0x%02X)" % auth_method
|
106
|
-
when 0x02 then
|
107
|
-
"Username/Password authentication (Code: 0x%02X)" % auth_method
|
108
|
-
when 0x03..0x7F then
|
109
|
-
"Method assigned by IANA (Code: 0x%02X)" % auth_method
|
110
|
-
when 0x80..0xFE then
|
111
|
-
"Method reserved for private use (Code: 0x%02X)" % auth_method
|
112
|
-
when 0xFF then
|
113
|
-
"Unsupported (Code: 0x%02X)" % auth_method
|
114
|
-
else
|
115
|
-
"Unknown (Code: 0x%02X)" % auth_method
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
# 0x00 = success
|
120
|
-
# any other value = failure, connection must be closed
|
121
|
-
def authentication_status(auth_status)
|
122
|
-
case auth_status
|
123
|
-
when 0x00 then
|
124
|
-
"Authentication success (Code: 0x%02X)" % auth_status
|
125
|
-
else
|
126
|
-
"Authentication failure (Code: 0x%02X)" % auth_status
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
class TCPSocket
|
134
|
-
|
135
|
-
class << self
|
136
|
-
|
137
|
-
def socks(&block)
|
138
|
-
@@socks ||= OpenStruct.new(Sockit::DEFAULT_CONFIG)
|
139
|
-
if block_given?
|
140
|
-
yield(@@socks)
|
141
|
-
else
|
142
|
-
@@socks
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
end
|
147
|
-
|
148
|
-
def socks(&block)
|
149
|
-
@@socks ||= OpenStruct.new(Sockit::DEFAULT_CONFIG)
|
54
|
+
def self.config(&block)
|
55
|
+
@@config ||= OpenStruct.new(Sockit::DEFAULT_CONFIG)
|
150
56
|
if block_given?
|
151
|
-
yield(@@
|
152
|
-
else
|
153
|
-
@@socks
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
alias :initialize_tcp :initialize
|
158
|
-
def initialize(remote_host, remote_port, local_host=nil, local_port=nil)
|
159
|
-
if (socks.host && socks.port && !socks.ignore.flatten.include?(remote_host))
|
160
|
-
Sockit.debug(:yellow, "Connecting to SOCKS server #{socks.host}:#{socks.port}")
|
161
|
-
initialize_tcp(socks.host, socks.port)
|
162
|
-
(socks.version.to_i == 5) and socks_authenticate
|
163
|
-
socks.host and socks_connect(remote_host, remote_port)
|
164
|
-
Sockit.debug(:green, "Connected to #{remote_host}:#{remote_port} via SOCKS server #{socks.host}:#{socks.port}")
|
57
|
+
yield(@@config)
|
165
58
|
else
|
166
|
-
|
167
|
-
initialize_tcp(remote_host, remote_port, local_host, local_port)
|
168
|
-
Sockit.debug(:green, "Connected to #{remote_host}:#{remote_port}")
|
59
|
+
@@config
|
169
60
|
end
|
170
61
|
end
|
171
62
|
|
172
|
-
def
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
# 0x02: Username/Password[11]
|
177
|
-
# 0x03-0x7F: methods assigned by IANA[12]
|
178
|
-
# 0x80-0xFE: methods reserved for private use
|
179
|
-
|
180
|
-
# The initial greeting from the client is
|
181
|
-
# field 1: SOCKS version number (must be 0x05 for this version)
|
182
|
-
# field 2: number of authentication methods supported, 1 byte
|
183
|
-
# field 3: authentication methods, variable length, 1 byte per method supported
|
184
|
-
if (socks.username || socks.password)
|
185
|
-
data = Array.new
|
186
|
-
data << [socks.version, 0x02, 0x02, 0x00].pack("C*")
|
187
|
-
data = data.flatten.join
|
188
|
-
|
189
|
-
socks.debug and Sockit.debug(:yellow, "Requesting username/password authentication")
|
190
|
-
socks.debug and Sockit.dump(:write, data)
|
191
|
-
write(data)
|
192
|
-
else
|
193
|
-
data = Array.new
|
194
|
-
data << [socks.version, 0x01, 0x00].pack("C*")
|
195
|
-
data = data.flatten.join
|
196
|
-
|
197
|
-
socks.debug and Sockit.debug(:yellow, "Requesting no authentication")
|
198
|
-
socks.debug and Sockit.dump(:write, data)
|
199
|
-
write(data)
|
200
|
-
end
|
201
|
-
|
202
|
-
# The server's choice is communicated:
|
203
|
-
# field 1: SOCKS version, 1 byte (0x05 for this version)
|
204
|
-
# field 2: chosen authentication method, 1 byte, or 0xFF if no acceptable methods were offered
|
205
|
-
socks.debug and Sockit.debug(:yellow, "Waiting for SOCKS authentication reply")
|
206
|
-
auth_reply = recv(2).unpack("C*")
|
207
|
-
socks.debug and Sockit.dump(:read, auth_reply)
|
208
|
-
server_socks_version = auth_reply[0]
|
209
|
-
server_auth_method = auth_reply[1]
|
210
|
-
|
211
|
-
if server_socks_version != socks.version
|
212
|
-
raise SockitError, "SOCKS server does not support version #{socks.version}!"
|
213
|
-
end
|
214
|
-
|
215
|
-
if server_auth_method == 0xFF
|
216
|
-
raise SockitError, Sockit.authentication_method(server_auth_method)
|
63
|
+
def config(&block)
|
64
|
+
@@config ||= OpenStruct.new(Sockit::DEFAULT_CONFIG)
|
65
|
+
if block_given?
|
66
|
+
yield(@@config)
|
217
67
|
else
|
218
|
-
|
219
|
-
end
|
220
|
-
|
221
|
-
# The subsequent authentication is method-dependent. Username and password authentication (method 0x02) is described in RFC 1929:
|
222
|
-
case server_auth_method
|
223
|
-
when 0x00 then
|
224
|
-
# No authentication
|
225
|
-
when 0x01 then
|
226
|
-
# GSSAPI
|
227
|
-
raise SockitError, "Authentication method GSSAPI not implemented"
|
228
|
-
when 0x02 then
|
229
|
-
# For username/password authentication the client's authentication request is
|
230
|
-
# field 1: version number, 1 byte (must be 0x01)
|
231
|
-
# field 2: username length, 1 byte
|
232
|
-
# field 3: username
|
233
|
-
# field 4: password length, 1 byte
|
234
|
-
# field 5: password
|
235
|
-
data = Array.new
|
236
|
-
data << [0x01].pack("C*")
|
237
|
-
data << [socks.username.length.to_i].pack("C*")
|
238
|
-
data << socks.username
|
239
|
-
data << [socks.password.length.to_i].pack("C*")
|
240
|
-
data << socks.password
|
241
|
-
data = data.flatten.join
|
242
|
-
|
243
|
-
socks.debug and Sockit.debug(:yellow, "Sending username and password")
|
244
|
-
socks.debug and Sockit.dump(:write, data)
|
245
|
-
write(data)
|
246
|
-
|
247
|
-
# Server response for username/password authentication:
|
248
|
-
# field 1: version, 1 byte
|
249
|
-
# field 2: status code, 1 byte.
|
250
|
-
# 0x00 = success
|
251
|
-
# any other value = failure, connection must be closed
|
252
|
-
socks.debug and Sockit.debug(:yellow, "Waiting for SOCKS authentication reply")
|
253
|
-
auth_reply = recv(2).unpack("C*")
|
254
|
-
socks.debug and Sockit.dump(:read, auth_reply)
|
255
|
-
version = auth_reply[0]
|
256
|
-
status_code = auth_reply[1]
|
257
|
-
|
258
|
-
if status_code == 0x00
|
259
|
-
socks.debug and Sockit.debug(:green, Sockit.authentication_status(status_code))
|
260
|
-
else
|
261
|
-
raise SockitError, Sockit.authentication_status(status_code)
|
262
|
-
end
|
68
|
+
@@config
|
263
69
|
end
|
264
|
-
|
265
70
|
end
|
266
71
|
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
# field 2: command code, 1 byte:
|
271
|
-
# 0x01 = establish a TCP/IP stream connection
|
272
|
-
# 0x02 = establish a TCP/IP port binding
|
273
|
-
# 0x03 = associate a UDP port
|
274
|
-
# field 3: reserved, must be 0x00
|
275
|
-
# field 4: address type, 1 byte:
|
276
|
-
# 0x01 = IPv4 address
|
277
|
-
# 0x03 = Domain name
|
278
|
-
# 0x04 = IPv6 address
|
279
|
-
# field 5: destination address of
|
280
|
-
# 4 bytes for IPv4 address
|
281
|
-
# 1 byte of name length followed by the name for Domain name
|
282
|
-
# 16 bytes for IPv6 address
|
283
|
-
# field 6: port number in a network byte order, 2 bytes
|
284
|
-
data = Array.new
|
285
|
-
data << [ socks.version.to_i, 0x01, 0x00 ].pack("C*")
|
72
|
+
extend Sockit::V5::Authentication
|
73
|
+
extend Sockit::V5::Connection
|
74
|
+
extend Sockit::V5::Support
|
286
75
|
|
287
|
-
|
288
|
-
|
289
|
-
remote_host = Resolv::DNS.new.getaddress(remote_host).to_s
|
290
|
-
end
|
76
|
+
extend Sockit::V4::Connection
|
77
|
+
extend Sockit::V4::Support
|
291
78
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
elsif remote_host =~ /^[:0-9a-f]+$/
|
296
|
-
data << [0x04].pack("C*")
|
297
|
-
data << [$1].pack("C*")
|
298
|
-
else
|
299
|
-
data << [0x03].pack("C*")
|
300
|
-
data << [remote_host.length.to_i].pack("C*")
|
301
|
-
data << remote_host
|
302
|
-
end
|
303
|
-
data << [remote_port].pack("n")
|
304
|
-
data = data.flatten.join
|
305
|
-
|
306
|
-
Sockit.debug(:yellow, "Requesting SOCKS connection to #{remote_host}:#{remote_port}")
|
307
|
-
socks.debug and Sockit.dump(:write, data)
|
308
|
-
write(data)
|
79
|
+
extend Sockit::Connection
|
80
|
+
extend Sockit::Support
|
81
|
+
end
|
309
82
|
|
310
|
-
|
311
|
-
# field 1: SOCKS protocol version, 1 byte (0x05 for this version)
|
312
|
-
# field 2: status, 1 byte:
|
313
|
-
# 0x00 = request granted
|
314
|
-
# 0x01 = general failure
|
315
|
-
# 0x02 = connection not allowed by ruleset
|
316
|
-
# 0x03 = network unreachable
|
317
|
-
# 0x04 = host unreachable
|
318
|
-
# 0x05 = connection refused by destination host
|
319
|
-
# 0x06 = TTL expired
|
320
|
-
# 0x07 = command not supported / protocol error
|
321
|
-
# 0x08 = address type not supported
|
322
|
-
# field 3: reserved, must be 0x00
|
323
|
-
# field 4: address type, 1 byte:
|
324
|
-
# 0x01 = IPv4 address
|
325
|
-
# 0x03 = Domain name
|
326
|
-
# 0x04 = IPv6 address
|
327
|
-
# field 5: destination address of
|
328
|
-
# 4 bytes for IPv4 address
|
329
|
-
# 1 byte of name length followed by the name for Domain name
|
330
|
-
# 16 bytes for IPv6 address
|
331
|
-
# field 6: network byte order port number, 2 bytes
|
332
|
-
socks.debug and Sockit.debug(:yellow, "Waiting for SOCKS connection reply")
|
333
|
-
packet = recv(4).unpack("C*")
|
334
|
-
socks.debug and Sockit.dump(:read, packet)
|
335
|
-
socks_version = packet[0]
|
336
|
-
status_code = packet[1]
|
337
|
-
reserved = packet[2]
|
338
|
-
address_type = packet[3]
|
83
|
+
class TCPSocket
|
339
84
|
|
340
|
-
|
341
|
-
|
85
|
+
alias :initialize_tcp :initialize
|
86
|
+
def initialize(remote_host, remote_port, local_host=nil, local_port=nil)
|
87
|
+
if Sockit.connect_via_socks?(remote_host)
|
88
|
+
initialize_tcp(Sockit.config.host, Sockit.config.port)
|
89
|
+
Sockit.perform_v5_authenticate(self) if Sockit.is_socks_v5?
|
90
|
+
Sockit.connect(self, remote_host, remote_port)
|
342
91
|
else
|
343
|
-
|
344
|
-
end
|
345
|
-
|
346
|
-
address_length = case address_type
|
347
|
-
when 0x01 then
|
348
|
-
4
|
349
|
-
when 0x03 then
|
350
|
-
data = recv(1).unpack("C*")
|
351
|
-
socks.debug and Sockit.dump(:read, data)
|
352
|
-
data[0]
|
353
|
-
when 0x04 then
|
354
|
-
16
|
92
|
+
Sockit.direct_connect(self, remote_host, remote_port, local_host, local_port)
|
355
93
|
end
|
356
|
-
address = recv(address_length).unpack("C*")
|
357
|
-
socks.debug and Sockit.dump(:read, address)
|
358
|
-
|
359
|
-
port = recv(2).unpack("n")
|
360
|
-
socks.debug and Sockit.dump(:read, port)
|
361
|
-
|
362
|
-
socks.debug and Sockit.debug(:green, [address, port].inspect)
|
363
94
|
end
|
364
|
-
|
365
95
|
end
|
data/sockit.gemspec
CHANGED
@@ -21,22 +21,32 @@
|
|
21
21
|
# -*- encoding: utf-8 -*-
|
22
22
|
require File.expand_path('../lib/sockit/version', __FILE__)
|
23
23
|
|
24
|
-
Gem::Specification.new do |
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
24
|
+
Gem::Specification.new do |spec|
|
25
|
+
spec.name = "sockit"
|
26
|
+
spec.version = Sockit::VERSION
|
27
|
+
spec.authors = %(Zachary Patten)
|
28
|
+
spec.email = [ %(zachary AT jovelabs DOT com) ]
|
29
|
+
spec.description = %(Transparent SOCKS v4 and SOCKS v5 support for TCPSocket)
|
30
|
+
spec.summary = %(Transparent SOCKS v4 and SOCKS v5 support for TCPSocket)
|
31
|
+
spec.homepage = %(https://github.com/zpatten/sockit)
|
32
|
+
spec.license = "Apache 2.0"
|
30
33
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
gem.require_paths = ["lib"]
|
36
|
-
gem.version = Sockit::VERSION
|
34
|
+
spec.files = `git ls-files`.split($/)
|
35
|
+
spec.executables = spec.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
36
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
37
|
+
spec.require_paths = ["lib"]
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
spec.required_ruby_version = '>= 2.0.0'
|
40
|
+
|
41
|
+
spec.add_development_dependency("pry")
|
42
|
+
spec.add_development_dependency("rake")
|
43
|
+
spec.add_development_dependency("rspec")
|
44
|
+
spec.add_development_dependency("yard")
|
45
|
+
spec.add_development_dependency("redcarpet")
|
46
|
+
spec.add_development_dependency("coveralls")
|
47
|
+
spec.add_development_dependency("yarjuf")
|
48
|
+
spec.add_development_dependency("simplecov-rcov")
|
49
|
+
|
50
|
+
spec.add_development_dependency("travis")
|
51
|
+
spec.add_development_dependency("websocket-native")
|
42
52
|
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
################################################################################
|
2
|
+
#
|
3
|
+
# Author: Zachary Patten <zachary AT jovelabs DOT com>
|
4
|
+
# Copyright: Copyright (c) Zachary Patten
|
5
|
+
# License: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
################################################################################
|
20
|
+
|
21
|
+
require "spec_helper"
|
22
|
+
|
23
|
+
describe Sockit do
|
24
|
+
|
25
|
+
subject { Sockit }
|
26
|
+
|
27
|
+
describe "class" do
|
28
|
+
|
29
|
+
it "should be Sockit" do
|
30
|
+
expect(subject).to be Sockit
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should have a default config" do
|
34
|
+
expect(subject.config.debug).to eq false
|
35
|
+
expect(subject.config.username).to eq nil
|
36
|
+
expect(subject.config.password).to eq nil
|
37
|
+
expect(subject.config.host).to eq nil
|
38
|
+
expect(subject.config.port).to eq nil
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should report as configured when it is" do
|
42
|
+
Sockit.config.version = 5
|
43
|
+
Sockit.config.host = "127.0.0.1"
|
44
|
+
Sockit.config.port = "1080"
|
45
|
+
|
46
|
+
expect(Sockit.is_configured?).to eq true
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should not report as configured when it is not" do
|
50
|
+
Sockit.config.version = 5
|
51
|
+
Sockit.config.host = "127.0.0.1"
|
52
|
+
Sockit.config.port = ""
|
53
|
+
|
54
|
+
expect(Sockit.is_configured?).to eq false
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should report as SOCKS v5 when configured as such" do
|
58
|
+
Sockit.config.version = 5
|
59
|
+
Sockit.config.host = "127.0.0.1"
|
60
|
+
Sockit.config.port = "1080"
|
61
|
+
|
62
|
+
expect(Sockit.is_socks_v5?).to eq true
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should not report as SOCKS v5 when configured as such" do
|
66
|
+
Sockit.config.version = 5
|
67
|
+
Sockit.config.host = ""
|
68
|
+
Sockit.config.port = "1080"
|
69
|
+
|
70
|
+
expect(Sockit.is_socks_v5?).to eq false
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should report as SOCKS v4 when configured as such" do
|
74
|
+
Sockit.config.version = 4
|
75
|
+
Sockit.config.host = "127.0.0.1"
|
76
|
+
Sockit.config.port = "1080"
|
77
|
+
|
78
|
+
expect(Sockit.is_socks_v4?).to eq true
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should not report as SOCKS v4 when configured as such" do
|
82
|
+
Sockit.config.version = 4
|
83
|
+
Sockit.config.host = ""
|
84
|
+
Sockit.config.port = "1080"
|
85
|
+
|
86
|
+
expect(Sockit.is_socks_v4?).to eq false
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
describe TCPSocket do
|
94
|
+
|
95
|
+
describe "connections" do
|
96
|
+
|
97
|
+
describe "direct" do
|
98
|
+
|
99
|
+
it "should allow a direct connection to github" do
|
100
|
+
Sockit.config do |config|
|
101
|
+
config.version = nil
|
102
|
+
config.host = nil
|
103
|
+
config.port = nil
|
104
|
+
end
|
105
|
+
|
106
|
+
socket = TCPSocket.new('github.com', '22')
|
107
|
+
data = socket.gets
|
108
|
+
expect(data).to match(/SSH/)
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "SOCKS v5" do
|
114
|
+
|
115
|
+
it "should allow a SOCKS v4 connection to github (no debug/no auth)" do
|
116
|
+
Sockit.config do |config|
|
117
|
+
config.debug = false
|
118
|
+
config.version = 4
|
119
|
+
config.host = "127.0.0.1"
|
120
|
+
config.port = "1080"
|
121
|
+
config.username = nil
|
122
|
+
config.password = nil
|
123
|
+
end
|
124
|
+
|
125
|
+
socket = TCPSocket.new('github.com', '22')
|
126
|
+
data = socket.gets
|
127
|
+
expect(data).to match(/SSH/)
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should allow a SOCKS v5 connection to github (no debug/no auth)" do
|
131
|
+
Sockit.config do |config|
|
132
|
+
config.debug = false
|
133
|
+
config.version = 5
|
134
|
+
config.host = "127.0.0.1"
|
135
|
+
config.port = "1080"
|
136
|
+
config.username = nil
|
137
|
+
config.password = nil
|
138
|
+
end
|
139
|
+
|
140
|
+
socket = TCPSocket.new('github.com', '22')
|
141
|
+
data = socket.gets
|
142
|
+
expect(data).to match(/SSH/)
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should allow a SOCKS v5 connection to github (debug/no auth)" do
|
146
|
+
$stdout = File.open('/dev/null', 'w')
|
147
|
+
|
148
|
+
Sockit.config do |config|
|
149
|
+
config.debug = true
|
150
|
+
config.version = 5
|
151
|
+
config.host = "127.0.0.1"
|
152
|
+
config.port = "1080"
|
153
|
+
config.username = nil
|
154
|
+
config.password = nil
|
155
|
+
end
|
156
|
+
|
157
|
+
socket = TCPSocket.new('github.com', '22')
|
158
|
+
data = socket.gets
|
159
|
+
expect(data).to match(/SSH/)
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should allow a SOCKS v5 connection to github (no debug/auth)" do
|
163
|
+
Sockit.config do |config|
|
164
|
+
config.debug = false
|
165
|
+
config.version = 5
|
166
|
+
config.host = "127.0.0.1"
|
167
|
+
config.port = "1081"
|
168
|
+
config.username = "root"
|
169
|
+
config.password = "none"
|
170
|
+
end
|
171
|
+
|
172
|
+
socket = TCPSocket.new('github.com', '22')
|
173
|
+
data = socket.gets
|
174
|
+
expect(data).to match(/SSH/)
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should allow a SOCKS v5 connection to github (debug/auth)" do
|
178
|
+
$stdout = File.open('/dev/null', 'w')
|
179
|
+
|
180
|
+
Sockit.config do |config|
|
181
|
+
config.debug = true
|
182
|
+
config.version = 5
|
183
|
+
config.host = "127.0.0.1"
|
184
|
+
config.port = "1081"
|
185
|
+
config.username = "root"
|
186
|
+
config.password = "none"
|
187
|
+
end
|
188
|
+
|
189
|
+
socket = TCPSocket.new('github.com', '22')
|
190
|
+
data = socket.gets
|
191
|
+
expect(data).to match(/SSH/)
|
192
|
+
end
|
193
|
+
|
194
|
+
it "should throw an exception if we use bad credentials (no debug/auth)" do
|
195
|
+
Sockit.config do |config|
|
196
|
+
config.debug = false
|
197
|
+
config.version = 5
|
198
|
+
config.host = "127.0.0.1"
|
199
|
+
config.port = "1081"
|
200
|
+
config.username = "root"
|
201
|
+
config.password = "blargh"
|
202
|
+
end
|
203
|
+
|
204
|
+
expect { TCPSocket.new('github.com', '22') }.to raise_exception(SockitError)
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
################################################################################
|
2
|
+
#
|
3
|
+
# Author: Zachary Patten <zachary AT jovelabs DOT com>
|
4
|
+
# Copyright: Copyright (c) Zachary Patten
|
5
|
+
# License: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
################################################################################
|
20
|
+
require 'simplecov'
|
21
|
+
require 'simplecov-rcov'
|
22
|
+
################################################################################
|
23
|
+
require 'coveralls'
|
24
|
+
Coveralls.wear!
|
25
|
+
################################################################################
|
26
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
|
27
|
+
[
|
28
|
+
SimpleCov::Formatter::HTMLFormatter,
|
29
|
+
SimpleCov::Formatter::RcovFormatter,
|
30
|
+
Coveralls::SimpleCov::Formatter
|
31
|
+
]
|
32
|
+
)
|
33
|
+
SimpleCov.start
|
34
|
+
################################################################################
|
35
|
+
require 'yarjuf'
|
36
|
+
################################################################################
|
37
|
+
|
38
|
+
require 'tempfile'
|
39
|
+
require 'sockit'
|
40
|
+
|
41
|
+
ENV['LOG_LEVEL'] = "DEBUG"
|
42
|
+
|
43
|
+
################################################################################
|