sockit 0.0.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/sockit.rb CHANGED
@@ -18,348 +18,78 @@
18
18
  #
19
19
  ################################################################################
20
20
 
21
- require "socket"
22
- require "resolv"
21
+ require 'socket'
22
+ require 'resolv'
23
+ require 'ostruct'
23
24
 
24
- require "sockit/version"
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 => ["127.0.0.1"],
32
- :debug => false
42
+ :ignore => %w( 127.0.0.1 ),
43
+ :debug => false
33
44
  }
34
45
 
35
46
  COLORS = {
36
- :reset => "\e[0m\e[37m",
37
- :red => "\e[1m\e[31m",
38
- :green => "\e[1m\e[32m",
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
- class << self
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(@@socks)
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
- Sockit.debug(:yellow, "Directly connecting to #{remote_host}:#{remote_port}")
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 socks_authenticate
173
- # The authentication methods supported are numbered as follows:
174
- # 0x00: No authentication
175
- # 0x01: GSSAPI[10]
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
- socks.debug and Sockit.debug(:green, Sockit.authentication_method(server_auth_method))
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
- def socks_connect(remote_host, remote_port)
268
- # The client's connection request is
269
- # field 1: SOCKS version number, 1 byte (must be 0x05 for this version)
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
- # when doing proxy mode on SS5; we seemingly need to resolve all names first.
288
- if remote_host !~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/
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
- if remote_host =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/
293
- data << [0x01].pack("C*")
294
- data << [$1.to_i, $2.to_i, $3.to_i, $4.to_i].pack("C*")
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
- # Server response:
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
- if status_code == 0x00
341
- socks.debug and Sockit.debug(:green, Sockit.status_message(status_code))
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
- raise SockitError, Sockit.status_message(status_code)
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 |gem|
25
- gem.authors = ["Zachary Patten"]
26
- gem.email = ["zachary@jovelabs.com"]
27
- gem.description = %q{Transparent SOCKS 5 support for TCPSocket}
28
- gem.summary = %q{Transparent SOCKS 5 support for TCPSocket}
29
- gem.homepage = "https://github.com/zpatten/sockit"
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
- gem.files = `git ls-files`.split($\)
32
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
33
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
34
- gem.name = "sockit"
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
- gem.add_development_dependency("pry")
39
- gem.add_development_dependency("rspec")
40
- gem.add_development_dependency("yard")
41
- gem.add_development_dependency("redcarpet")
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
@@ -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
+ ################################################################################