sockit 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/.rspec +1 -0
- data/.rvmrc +1 -0
- data/.rvmrc.template +1 -0
- data/.travis.yml +11 -0
- data/README.md +42 -7
- data/bin/sockit +11 -0
- data/lib/sockit/version.rb +1 -1
- data/lib/sockit.rb +342 -1
- data/sockit.gemspec +5 -3
- metadata +29 -7
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
-c -b -fd
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use ruby-1.9.3@sockit --create
|
data/.rvmrc.template
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use ruby-1.9.3@sockit --create
|
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Sockit
|
2
2
|
|
3
|
-
|
3
|
+
Transparent SOCKS 5 support for TCPSockets
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -18,12 +18,47 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
|
21
|
+
By loading the gem TCPSocket will get monkey patched adding seamless transparent SOCKS proxy support. I favor using SS5 for a SOCKS server, so at this point I'm uncertain of absolute compatibility with other SOCKS servers. I'm following the RFC here; so if (insert other SOCKS server flavor here) follows the RFC everything is in theory compatible.
|
22
|
+
|
23
|
+
### Configuration
|
24
|
+
|
25
|
+
You can configure on the singleton class or an instance of the class. The SOCKS configuration is stored in a class variable; so it is shared across all TCPSocket instances and the singleton, thus changing the configuration in one instance will also affect all other instances. The configuration is stored in an OpenStruct; you can reference `socks` with a block as shown, where the configuration OpenStruct is yielded to the block; or without in which case the configuration OpenStruct itself is returned.
|
26
|
+
|
27
|
+
The defaults are as follows:
|
28
|
+
|
29
|
+
TCPSocket.socks do |config|
|
30
|
+
config.version = 5
|
31
|
+
config.ignore = ["127.0.0.1"]
|
32
|
+
config.debug = false
|
33
|
+
end
|
34
|
+
|
35
|
+
Specify your SOCKS server and port:
|
36
|
+
|
37
|
+
TCPSocket.socks do |config|
|
38
|
+
config.host = "127.0.0.1"
|
39
|
+
config.port = "1080"
|
40
|
+
end
|
41
|
+
|
42
|
+
If you want to use username/password authentication:
|
43
|
+
|
44
|
+
TCPSocket.socks do |config|
|
45
|
+
config.username = "username"
|
46
|
+
config.password = "password"
|
47
|
+
end
|
48
|
+
|
49
|
+
Turn on debug output:
|
50
|
+
|
51
|
+
TCPSocket.socks do |config|
|
52
|
+
config.debug = true
|
53
|
+
end
|
54
|
+
|
55
|
+
Ignore some more hosts:
|
56
|
+
|
57
|
+
TCPSocket.socks do |config|
|
58
|
+
config.ignore << "192.168.0.1"
|
59
|
+
end
|
60
|
+
|
22
61
|
|
23
62
|
## Contributing
|
24
63
|
|
25
|
-
|
26
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
-
3. Commit your changes (`git commit -am 'Added some feature'`)
|
28
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
-
5. Create new Pull Request
|
64
|
+
I await your pull request.
|
data/bin/sockit
ADDED
data/lib/sockit/version.rb
CHANGED
data/lib/sockit.rb
CHANGED
@@ -1,5 +1,346 @@
|
|
1
|
+
require "socket"
|
2
|
+
require "resolv"
|
3
|
+
|
1
4
|
require "sockit/version"
|
2
5
|
|
6
|
+
class SockitError < RuntimeError; end
|
7
|
+
|
3
8
|
module Sockit
|
4
|
-
|
9
|
+
DEFAULT_CONFIG = {
|
10
|
+
:version => 5,
|
11
|
+
:ignore => ["127.0.0.1"],
|
12
|
+
:debug => false
|
13
|
+
}
|
14
|
+
|
15
|
+
COLORS = {
|
16
|
+
:reset => "\e[0m\e[37m",
|
17
|
+
:red => "\e[1m\e[31m",
|
18
|
+
:green => "\e[1m\e[32m",
|
19
|
+
:yellow => "\e[1m\e[33m"
|
20
|
+
}
|
21
|
+
|
22
|
+
class << self
|
23
|
+
|
24
|
+
def debug(color, message)
|
25
|
+
timestamp = Time.now.utc
|
26
|
+
puts("%s%s.%06d %s%s" % [COLORS[color], timestamp.strftime("%Y-%m-%d|%H:%M:%S"), timestamp.usec, message, COLORS[:reset]])
|
27
|
+
end
|
28
|
+
|
29
|
+
def dump(action, data)
|
30
|
+
bytes = Array.new
|
31
|
+
chars = Array.new
|
32
|
+
for x in 0..(data.length - 1) do
|
33
|
+
bytes << ("%03d" % data[x].ord)
|
34
|
+
chars << ("%03s" % (data[x] =~ /^\w+$/ ? data[x].chr : "..."))
|
35
|
+
end
|
36
|
+
debug(:red, "#{action.to_s.upcase}: #{bytes.join(" ")}#{COLORS[:reset]}")
|
37
|
+
debug(:red, "#{action.to_s.upcase}: #{chars.join(" ")}#{COLORS[:reset]}")
|
38
|
+
end
|
39
|
+
|
40
|
+
# 0x00 = request granted
|
41
|
+
# 0x01 = general failure
|
42
|
+
# 0x02 = connection not allowed by ruleset
|
43
|
+
# 0x03 = network unreachable
|
44
|
+
# 0x04 = host unreachable
|
45
|
+
# 0x05 = connection refused by destination host
|
46
|
+
# 0x06 = TTL expired
|
47
|
+
# 0x07 = command not supported / protocol error
|
48
|
+
# 0x08 = address type not supported
|
49
|
+
def status_message(status_code)
|
50
|
+
case status_code
|
51
|
+
when 0x00 then
|
52
|
+
"Request granted (Code: 0x%02X)" % status_code
|
53
|
+
when 0x01 then
|
54
|
+
"General failure (Code: 0x%02X)" % status_code
|
55
|
+
when 0x02 then
|
56
|
+
"Connection not allowed by ruleset (Code: 0x%02X)" % status_code
|
57
|
+
when 0x03 then
|
58
|
+
"Network unreachable (Code: 0x%02X)" % status_code
|
59
|
+
when 0x04 then
|
60
|
+
"Host unreachable (Code: 0x%02X)" % status_code
|
61
|
+
when 0x05 then
|
62
|
+
"Connection refused by destination host (Code: 0x%02X)" % status_code
|
63
|
+
when 0x06 then
|
64
|
+
"TTL expired (Code: 0x%02X)" % status_code
|
65
|
+
when 0x07 then
|
66
|
+
"Command not supported / Protocol error (Code: 0x%02X)" % status_code
|
67
|
+
when 0x08 then
|
68
|
+
"Address type not supported (Code: 0x%02X)" % status_code
|
69
|
+
else
|
70
|
+
"Unknown (Code: 0x%02X)" % status_code
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# The authentication methods supported are numbered as follows:
|
75
|
+
# 0x00: No authentication
|
76
|
+
# 0x01: GSSAPI[10]
|
77
|
+
# 0x02: Username/Password[11]
|
78
|
+
# 0x03-0x7F: methods assigned by IANA[12]
|
79
|
+
# 0x80-0xFE: methods reserved for private use
|
80
|
+
def authentication_method(auth_method)
|
81
|
+
case auth_method
|
82
|
+
when 0x00 then
|
83
|
+
"No authentication (Code: 0x%02X)" % auth_method
|
84
|
+
when 0x01 then
|
85
|
+
"GSSAPI authentication (Code: 0x%02X)" % auth_method
|
86
|
+
when 0x02 then
|
87
|
+
"Username/Password authentication (Code: 0x%02X)" % auth_method
|
88
|
+
when 0x03..0x7F then
|
89
|
+
"Method assigned by IANA (Code: 0x%02X)" % auth_method
|
90
|
+
when 0x80..0xFE then
|
91
|
+
"Method reserved for private use (Code: 0x%02X)" % auth_method
|
92
|
+
when 0xFF then
|
93
|
+
"Unsupported (Code: 0x%02X)" % auth_method
|
94
|
+
else
|
95
|
+
"Unknown (Code: 0x%02X)" % auth_method
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# 0x00 = success
|
100
|
+
# any other value = failure, connection must be closed
|
101
|
+
def authentication_status(auth_status)
|
102
|
+
case auth_status
|
103
|
+
when 0x00 then
|
104
|
+
"Authentication success (Code: 0x%02X)" % auth_status
|
105
|
+
else
|
106
|
+
"Authentication failure (Code: 0x%02X)" % auth_status
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
class TCPSocket
|
114
|
+
|
115
|
+
class << self
|
116
|
+
|
117
|
+
def socks(&block)
|
118
|
+
@@socks ||= OpenStruct.new(Sockit::DEFAULT_CONFIG)
|
119
|
+
if block_given?
|
120
|
+
yield(@@socks)
|
121
|
+
else
|
122
|
+
@@socks
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
def socks(&block)
|
129
|
+
@@socks ||= OpenStruct.new(Sockit::DEFAULT_CONFIG)
|
130
|
+
if block_given?
|
131
|
+
yield(@@socks)
|
132
|
+
else
|
133
|
+
@@socks
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
alias :initialize_tcp :initialize
|
138
|
+
def initialize(remote_host, remote_port, local_host=nil, local_port=nil)
|
139
|
+
if (socks.host && socks.port && !socks.ignore.include?(remote_host))
|
140
|
+
Sockit.debug(:yellow, "Connecting to SOCKS server #{socks.host}:#{socks.port}")
|
141
|
+
initialize_tcp(socks.host, socks.port)
|
142
|
+
|
143
|
+
(socks.version.to_i == 5) and socks_authenticate
|
144
|
+
socks.host and socks_connect(remote_host, remote_port)
|
145
|
+
Sockit.debug(:green, "Connected to #{remote_host}:#{remote_port} via SOCKS server #{socks.host}:#{socks.port}")
|
146
|
+
else
|
147
|
+
Sockit.debug(:yellow, "Directly connecting to #{remote_host}:#{remote_port}")
|
148
|
+
initialize_tcp(remote_host, remote_port, local_host, local_port)
|
149
|
+
Sockit.debug(:green, "Connected to #{remote_host}:#{remote_port}")
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def socks_authenticate
|
154
|
+
# The authentication methods supported are numbered as follows:
|
155
|
+
# 0x00: No authentication
|
156
|
+
# 0x01: GSSAPI[10]
|
157
|
+
# 0x02: Username/Password[11]
|
158
|
+
# 0x03-0x7F: methods assigned by IANA[12]
|
159
|
+
# 0x80-0xFE: methods reserved for private use
|
160
|
+
|
161
|
+
# The initial greeting from the client is
|
162
|
+
# field 1: SOCKS version number (must be 0x05 for this version)
|
163
|
+
# field 2: number of authentication methods supported, 1 byte
|
164
|
+
# field 3: authentication methods, variable length, 1 byte per method supported
|
165
|
+
if (socks.username || socks.password)
|
166
|
+
data = Array.new
|
167
|
+
data << [socks.version, 0x02, 0x02, 0x00].pack("C*")
|
168
|
+
data = data.flatten.join
|
169
|
+
|
170
|
+
socks.debug and Sockit.debug(:yellow, "Requesting username/password authentication")
|
171
|
+
socks.debug and Sockit.dump(:write, data)
|
172
|
+
write(data)
|
173
|
+
else
|
174
|
+
data = Array.new
|
175
|
+
data << [socks.version, 0x01, 0x00].pack("C*")
|
176
|
+
data = data.flatten.join
|
177
|
+
|
178
|
+
socks.debug and Sockit.debug(:yellow, "Requesting no authentication")
|
179
|
+
socks.debug and Sockit.dump(:write, data)
|
180
|
+
write(data)
|
181
|
+
end
|
182
|
+
|
183
|
+
# The server's choice is communicated:
|
184
|
+
# field 1: SOCKS version, 1 byte (0x05 for this version)
|
185
|
+
# field 2: chosen authentication method, 1 byte, or 0xFF if no acceptable methods were offered
|
186
|
+
socks.debug and Sockit.debug(:yellow, "Waiting for SOCKS authentication reply")
|
187
|
+
auth_reply = recv(2).unpack("C*")
|
188
|
+
socks.debug and Sockit.dump(:read, auth_reply)
|
189
|
+
server_socks_version = auth_reply[0]
|
190
|
+
server_auth_method = auth_reply[1]
|
191
|
+
|
192
|
+
if server_socks_version != socks.version
|
193
|
+
raise SockitError, "SOCKS server does not support version #{socks.version}!"
|
194
|
+
end
|
195
|
+
|
196
|
+
if server_auth_method == 0xFF
|
197
|
+
raise SockitError, Sockit.authentication_method(server_auth_method)
|
198
|
+
else
|
199
|
+
socks.debug and Sockit.debug(:green, Sockit.authentication_method(server_auth_method))
|
200
|
+
end
|
201
|
+
|
202
|
+
# The subsequent authentication is method-dependent. Username and password authentication (method 0x02) is described in RFC 1929:
|
203
|
+
case server_auth_method
|
204
|
+
when 0x00 then
|
205
|
+
# No authentication
|
206
|
+
when 0x01 then
|
207
|
+
# GSSAPI
|
208
|
+
raise SockitError, "Authentication method GSSAPI not implemented"
|
209
|
+
when 0x02 then
|
210
|
+
# For username/password authentication the client's authentication request is
|
211
|
+
# field 1: version number, 1 byte (must be 0x01)
|
212
|
+
# field 2: username length, 1 byte
|
213
|
+
# field 3: username
|
214
|
+
# field 4: password length, 1 byte
|
215
|
+
# field 5: password
|
216
|
+
data = Array.new
|
217
|
+
data << [0x01].pack("C*")
|
218
|
+
data << [socks.username.length.to_i].pack("C*")
|
219
|
+
data << socks.username
|
220
|
+
data << [socks.password.length.to_i].pack("C*")
|
221
|
+
data << socks.password
|
222
|
+
data = data.flatten.join
|
223
|
+
|
224
|
+
socks.debug and Sockit.debug(:yellow, "Sending username and password")
|
225
|
+
socks.debug and Sockit.dump(:write, data)
|
226
|
+
write(data)
|
227
|
+
|
228
|
+
# Server response for username/password authentication:
|
229
|
+
# field 1: version, 1 byte
|
230
|
+
# field 2: status code, 1 byte.
|
231
|
+
# 0x00 = success
|
232
|
+
# any other value = failure, connection must be closed
|
233
|
+
socks.debug and Sockit.debug(:yellow, "Waiting for SOCKS authentication reply")
|
234
|
+
auth_reply = recv(2).unpack("C*")
|
235
|
+
socks.debug and Sockit.dump(:read, auth_reply)
|
236
|
+
version = auth_reply[0]
|
237
|
+
status_code = auth_reply[1]
|
238
|
+
|
239
|
+
if status_code == 0x00
|
240
|
+
socks.debug and Sockit.debug(:green, Sockit.authentication_status(status_code))
|
241
|
+
else
|
242
|
+
raise SockitError, Sockit.authentication_status(status_code)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
247
|
+
|
248
|
+
def socks_connect(remote_host, remote_port)
|
249
|
+
# The client's connection request is
|
250
|
+
# field 1: SOCKS version number, 1 byte (must be 0x05 for this version)
|
251
|
+
# field 2: command code, 1 byte:
|
252
|
+
# 0x01 = establish a TCP/IP stream connection
|
253
|
+
# 0x02 = establish a TCP/IP port binding
|
254
|
+
# 0x03 = associate a UDP port
|
255
|
+
# field 3: reserved, must be 0x00
|
256
|
+
# field 4: address type, 1 byte:
|
257
|
+
# 0x01 = IPv4 address
|
258
|
+
# 0x03 = Domain name
|
259
|
+
# 0x04 = IPv6 address
|
260
|
+
# field 5: destination address of
|
261
|
+
# 4 bytes for IPv4 address
|
262
|
+
# 1 byte of name length followed by the name for Domain name
|
263
|
+
# 16 bytes for IPv6 address
|
264
|
+
# field 6: port number in a network byte order, 2 bytes
|
265
|
+
data = Array.new
|
266
|
+
data << [ socks.version.to_i, 0x01, 0x00 ].pack("C*")
|
267
|
+
|
268
|
+
# when doing proxy mode on SS5; we seemingly need to resolve all names first.
|
269
|
+
if remote_host !~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/
|
270
|
+
remote_host = Resolv::DNS.new.getaddress(remote_host).to_s
|
271
|
+
end
|
272
|
+
|
273
|
+
if remote_host =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/
|
274
|
+
data << [0x01].pack("C*")
|
275
|
+
data << [$1.to_i, $2.to_i, $3.to_i, $4.to_i].pack("C*")
|
276
|
+
elsif remote_host =~ /^[:0-9a-f]+$/
|
277
|
+
data << [0x04].pack("C*")
|
278
|
+
data << [$1].pack("C*")
|
279
|
+
else
|
280
|
+
data << [0x03].pack("C*")
|
281
|
+
data << [remote_host.length.to_i].pack("C*")
|
282
|
+
data << remote_host
|
283
|
+
end
|
284
|
+
data << [remote_port].pack("n")
|
285
|
+
data = data.flatten.join
|
286
|
+
|
287
|
+
Sockit.debug(:yellow, "Requesting SOCKS connection to #{remote_host}:#{remote_port}")
|
288
|
+
socks.debug and Sockit.dump(:write, data)
|
289
|
+
write(data)
|
290
|
+
|
291
|
+
# Server response:
|
292
|
+
# field 1: SOCKS protocol version, 1 byte (0x05 for this version)
|
293
|
+
# field 2: status, 1 byte:
|
294
|
+
# 0x00 = request granted
|
295
|
+
# 0x01 = general failure
|
296
|
+
# 0x02 = connection not allowed by ruleset
|
297
|
+
# 0x03 = network unreachable
|
298
|
+
# 0x04 = host unreachable
|
299
|
+
# 0x05 = connection refused by destination host
|
300
|
+
# 0x06 = TTL expired
|
301
|
+
# 0x07 = command not supported / protocol error
|
302
|
+
# 0x08 = address type not supported
|
303
|
+
# field 3: reserved, must be 0x00
|
304
|
+
# field 4: address type, 1 byte:
|
305
|
+
# 0x01 = IPv4 address
|
306
|
+
# 0x03 = Domain name
|
307
|
+
# 0x04 = IPv6 address
|
308
|
+
# field 5: destination address of
|
309
|
+
# 4 bytes for IPv4 address
|
310
|
+
# 1 byte of name length followed by the name for Domain name
|
311
|
+
# 16 bytes for IPv6 address
|
312
|
+
# field 6: network byte order port number, 2 bytes
|
313
|
+
socks.debug and Sockit.debug(:yellow, "Waiting for SOCKS connection reply")
|
314
|
+
packet = recv(4).unpack("C*")
|
315
|
+
socks.debug and Sockit.dump(:read, packet)
|
316
|
+
socks_version = packet[0]
|
317
|
+
status_code = packet[1]
|
318
|
+
reserved = packet[2]
|
319
|
+
address_type = packet[3]
|
320
|
+
|
321
|
+
if status_code == 0x00
|
322
|
+
socks.debug and Sockit.debug(:green, Sockit.status_message(status_code))
|
323
|
+
else
|
324
|
+
raise SockitError, Sockit.status_message(status_code)
|
325
|
+
end
|
326
|
+
|
327
|
+
address_length = case address_type
|
328
|
+
when 0x01 then
|
329
|
+
4
|
330
|
+
when 0x03 then
|
331
|
+
data = recv(1).unpack("C*")
|
332
|
+
socks.debug and Sockit.dump(:read, data)
|
333
|
+
data[0]
|
334
|
+
when 0x04 then
|
335
|
+
16
|
336
|
+
end
|
337
|
+
address = recv(address_length).unpack("C*")
|
338
|
+
socks.debug and Sockit.dump(:read, address)
|
339
|
+
|
340
|
+
port = recv(2).unpack("n")
|
341
|
+
socks.debug and Sockit.dump(:read, port)
|
342
|
+
|
343
|
+
socks.debug and Sockit.debug(:green, [address, port].inspect)
|
344
|
+
end
|
345
|
+
|
5
346
|
end
|
data/sockit.gemspec
CHANGED
@@ -4,9 +4,9 @@ require File.expand_path('../lib/sockit/version', __FILE__)
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ["Zachary Patten"]
|
6
6
|
gem.email = ["zachary@jovelabs.com"]
|
7
|
-
gem.description = %q{SOCKS
|
8
|
-
gem.summary = %q{SOCKS
|
9
|
-
gem.homepage = ""
|
7
|
+
gem.description = %q{Transparent SOCKS 5 support for TCPSockets}
|
8
|
+
gem.summary = %q{Transparent SOCKS 5 support for TCPSockets}
|
9
|
+
gem.homepage = "https://github.com/jovelabs/sockit"
|
10
10
|
|
11
11
|
gem.files = `git ls-files`.split($\)
|
12
12
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
@@ -14,4 +14,6 @@ Gem::Specification.new do |gem|
|
|
14
14
|
gem.name = "sockit"
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = Sockit::VERSION
|
17
|
+
|
18
|
+
gem.add_development_dependency("pry")
|
17
19
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sockit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,24 +9,46 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
13
|
-
dependencies:
|
14
|
-
|
12
|
+
date: 2012-09-04 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: pry
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
description: Transparent SOCKS 5 support for TCPSockets
|
15
31
|
email:
|
16
32
|
- zachary@jovelabs.com
|
17
|
-
executables:
|
33
|
+
executables:
|
34
|
+
- sockit
|
18
35
|
extensions: []
|
19
36
|
extra_rdoc_files: []
|
20
37
|
files:
|
21
38
|
- .gitignore
|
39
|
+
- .rspec
|
40
|
+
- .rvmrc
|
41
|
+
- .rvmrc.template
|
42
|
+
- .travis.yml
|
22
43
|
- Gemfile
|
23
44
|
- LICENSE
|
24
45
|
- README.md
|
25
46
|
- Rakefile
|
47
|
+
- bin/sockit
|
26
48
|
- lib/sockit.rb
|
27
49
|
- lib/sockit/version.rb
|
28
50
|
- sockit.gemspec
|
29
|
-
homepage:
|
51
|
+
homepage: https://github.com/jovelabs/sockit
|
30
52
|
licenses: []
|
31
53
|
post_install_message:
|
32
54
|
rdoc_options: []
|
@@ -49,5 +71,5 @@ rubyforge_project:
|
|
49
71
|
rubygems_version: 1.8.24
|
50
72
|
signing_key:
|
51
73
|
specification_version: 3
|
52
|
-
summary: SOCKS
|
74
|
+
summary: Transparent SOCKS 5 support for TCPSockets
|
53
75
|
test_files: []
|