socksify 1.1.0 → 1.1.1
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/doc/index.html +7 -18
- data/lib/socksify.rb +21 -21
- data/lib/socksify.rb.orig +244 -0
- metadata +9 -6
data/doc/index.html
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
<?xml version="1.0" encoding="utf-8"?>
|
2
|
-
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/
|
2
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
3
3
|
|
4
4
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
5
5
|
<head>
|
@@ -77,10 +77,10 @@ rubyforge_www = TCPSocket.new("rubyforge.org", 80)
|
|
77
77
|
<h2>Development</h2>
|
78
78
|
|
79
79
|
<p>
|
80
|
-
The <a href="http://
|
80
|
+
The <a href="http://github.com/astro/socksify-ruby/">repository</a>
|
81
81
|
can be checked out with:
|
82
82
|
</p>
|
83
|
-
<pre>$ git-clone
|
83
|
+
<pre>$ git-clone git://github.com/astro/socksify-ruby.git</pre>
|
84
84
|
<p>
|
85
85
|
Send patches via E-Mail.
|
86
86
|
</p>
|
@@ -106,21 +106,10 @@ rubyforge_www = TCPSocket.new("rubyforge.org", 80)
|
|
106
106
|
|
107
107
|
<h2>License</h2>
|
108
108
|
<p>
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
</p>
|
114
|
-
<p>
|
115
|
-
This program is distributed in the hope that it will be
|
116
|
-
useful, but WITHOUT ANY WARRANTY; without even the implied
|
117
|
-
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
118
|
-
PURPOSE. See the GNU General Public License for more details.
|
119
|
-
</p>
|
120
|
-
<p>
|
121
|
-
You should have received a copy of the GNU General Public
|
122
|
-
License along with this program. If not, see
|
123
|
-
<<a href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>.
|
109
|
+
SOCKSify Ruby is distributed under the terms of the GNU
|
110
|
+
General Public License version 3 (see
|
111
|
+
file <code>COPYING</code>) or the Ruby License (see
|
112
|
+
file <code>LICENSE</code>) at your option.
|
124
113
|
</p>
|
125
114
|
</div>
|
126
115
|
</body>
|
data/lib/socksify.rb
CHANGED
@@ -91,13 +91,13 @@ end
|
|
91
91
|
|
92
92
|
class TCPSocket
|
93
93
|
def self.socks_server
|
94
|
-
@@socks_server
|
94
|
+
@@socks_server ||= nil
|
95
95
|
end
|
96
96
|
def self.socks_server=(host)
|
97
97
|
@@socks_server = host
|
98
98
|
end
|
99
99
|
def self.socks_port
|
100
|
-
@@socks_port
|
100
|
+
@@socks_port ||= nil
|
101
101
|
end
|
102
102
|
def self.socks_port=(port)
|
103
103
|
@@socks_port = port
|
@@ -139,11 +139,11 @@ class TCPSocket
|
|
139
139
|
write "\005\001\000"
|
140
140
|
Socksify::debug_debug "Waiting for authentication reply"
|
141
141
|
auth_reply = recv(2)
|
142
|
-
if auth_reply[0] !=
|
143
|
-
raise SOCKSError.new("SOCKS version #{auth_reply[0]} not supported")
|
142
|
+
if auth_reply[0..0] != "\004" and auth_reply[0..0] != "\005"
|
143
|
+
raise SOCKSError.new("SOCKS version #{auth_reply[0..0]} not supported")
|
144
144
|
end
|
145
|
-
if auth_reply[1] !=
|
146
|
-
raise SOCKSError.new("SOCKS authentication method #{auth_reply[1]} neither requested nor supported")
|
145
|
+
if auth_reply[1..1] != "\000"
|
146
|
+
raise SOCKSError.new("SOCKS authentication method #{auth_reply[1..1]} neither requested nor supported")
|
147
147
|
end
|
148
148
|
end
|
149
149
|
|
@@ -173,30 +173,30 @@ class TCPSocket
|
|
173
173
|
def socks_receive_reply
|
174
174
|
Socksify::debug_debug "Waiting for SOCKS reply"
|
175
175
|
connect_reply = recv(4)
|
176
|
-
if connect_reply[0] !=
|
177
|
-
raise SOCKSError.new("SOCKS version #{connect_reply[0]} is not 5")
|
176
|
+
if connect_reply[0..0] != "\005"
|
177
|
+
raise SOCKSError.new("SOCKS version #{connect_reply[0..0]} is not 5")
|
178
178
|
end
|
179
|
-
if connect_reply[1] !=
|
180
|
-
raise SOCKSError.for_response_code(connect_reply[1])
|
179
|
+
if connect_reply[1..1] != "\000"
|
180
|
+
raise SOCKSError.for_response_code(connect_reply.bytes.to_a[1])
|
181
181
|
end
|
182
182
|
Socksify::debug_debug "Waiting for bind_addr"
|
183
|
-
bind_addr_len = case connect_reply[3]
|
184
|
-
when
|
183
|
+
bind_addr_len = case connect_reply[3..3]
|
184
|
+
when "\001"
|
185
185
|
4
|
186
|
-
when
|
187
|
-
recv(1)
|
188
|
-
when
|
186
|
+
when "\003"
|
187
|
+
recv(1).bytes.first
|
188
|
+
when "\004"
|
189
189
|
16
|
190
190
|
else
|
191
|
-
raise SOCKSError.for_response_code(connect_reply[3])
|
191
|
+
raise SOCKSError.for_response_code(connect_reply.bytes.to_a[3])
|
192
192
|
end
|
193
193
|
bind_addr_s = recv(bind_addr_len)
|
194
|
-
bind_addr = case connect_reply[3]
|
195
|
-
when
|
196
|
-
|
197
|
-
when
|
194
|
+
bind_addr = case connect_reply[3..3]
|
195
|
+
when "\001"
|
196
|
+
bind_addr_s.bytes.to_a.join('.')
|
197
|
+
when "\003"
|
198
198
|
bind_addr_s
|
199
|
-
when
|
199
|
+
when "\004" # Untested!
|
200
200
|
i = 0
|
201
201
|
ip6 = ""
|
202
202
|
bind_addr_s.each_byte do |b|
|
@@ -0,0 +1,244 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright (C) 2007 Stephan Maka <stephan@spaceboyz.net>
|
3
|
+
|
4
|
+
This program is free software: you can redistribute it and/or modify
|
5
|
+
it under the terms of the GNU General Public License as published by
|
6
|
+
the Free Software Foundation, either version 3 of the License, or
|
7
|
+
(at your option) any later version.
|
8
|
+
|
9
|
+
This program is distributed in the hope that it will be useful,
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
GNU General Public License for more details.
|
13
|
+
|
14
|
+
You should have received a copy of the GNU General Public License
|
15
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
=end
|
17
|
+
|
18
|
+
require 'socket'
|
19
|
+
require 'socksify_debug'
|
20
|
+
|
21
|
+
class SOCKSError < RuntimeError
|
22
|
+
def initialize(msg)
|
23
|
+
Socksify::debug_error("#{self.class}: #{msg}")
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
class ServerFailure < SOCKSError
|
28
|
+
def initialize
|
29
|
+
super("general SOCKS server failure")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
class NotAllowed < SOCKSError
|
33
|
+
def initialize
|
34
|
+
super("connection not allowed by ruleset")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
class NetworkUnreachable < SOCKSError
|
38
|
+
def initialize
|
39
|
+
super("Network unreachable")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
class HostUnreachable < SOCKSError
|
43
|
+
def initialize
|
44
|
+
super("Host unreachable")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
class ConnectionRefused < SOCKSError
|
48
|
+
def initialize
|
49
|
+
super("Connection refused")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
class TTLExpired < SOCKSError
|
53
|
+
def initialize
|
54
|
+
super("TTL expired")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
class CommandNotSupported < SOCKSError
|
58
|
+
def initialize
|
59
|
+
super("Command not supported")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
class AddressTypeNotSupported < SOCKSError
|
63
|
+
def initialize
|
64
|
+
super("Address type not supported")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.for_response_code(code)
|
69
|
+
case code
|
70
|
+
when 1
|
71
|
+
ServerFailure
|
72
|
+
when 2
|
73
|
+
NotAllowed
|
74
|
+
when 3
|
75
|
+
NetworkUnreachable
|
76
|
+
when 4
|
77
|
+
HostUnreachable
|
78
|
+
when 5
|
79
|
+
ConnectionRefused
|
80
|
+
when 6
|
81
|
+
TTLExpired
|
82
|
+
when 7
|
83
|
+
CommandNotSupported
|
84
|
+
when 8
|
85
|
+
AddressTypeNotSupported
|
86
|
+
else
|
87
|
+
self
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class TCPSocket
|
93
|
+
def self.socks_server
|
94
|
+
@@socks_server
|
95
|
+
end
|
96
|
+
def self.socks_server=(host)
|
97
|
+
@@socks_server = host
|
98
|
+
end
|
99
|
+
def self.socks_port
|
100
|
+
@@socks_port
|
101
|
+
end
|
102
|
+
def self.socks_port=(port)
|
103
|
+
@@socks_port = port
|
104
|
+
end
|
105
|
+
def self.socks_ignores
|
106
|
+
@@socks_ignores ||= []
|
107
|
+
end
|
108
|
+
def self.socks_ignores=(ignores)
|
109
|
+
@@socks_ignores = ignores
|
110
|
+
end
|
111
|
+
|
112
|
+
alias :initialize_tcp :initialize
|
113
|
+
|
114
|
+
# See http://tools.ietf.org/html/rfc1928
|
115
|
+
def initialize(host=nil, port=0, local_host="0.0.0.0", local_port=0)
|
116
|
+
socks_server = self.class.socks_server
|
117
|
+
socks_port = self.class.socks_port
|
118
|
+
socks_ignores = self.class.socks_ignores
|
119
|
+
|
120
|
+
if socks_server and socks_port and not socks_ignores.include?(host)
|
121
|
+
Socksify::debug_notice "Connecting to SOCKS server #{socks_server}:#{socks_port}"
|
122
|
+
initialize_tcp socks_server, socks_port
|
123
|
+
|
124
|
+
socks_authenticate
|
125
|
+
|
126
|
+
if host
|
127
|
+
socks_connect(host, port)
|
128
|
+
end
|
129
|
+
else
|
130
|
+
Socksify::debug_notice "Connecting directly to #{host}:#{port}"
|
131
|
+
initialize_tcp host, port, local_host, local_port
|
132
|
+
Socksify::debug_debug "Connected to #{host}:#{port}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Authentication
|
137
|
+
def socks_authenticate
|
138
|
+
Socksify::debug_debug "Sending no authentication"
|
139
|
+
write "\005\001\000"
|
140
|
+
Socksify::debug_debug "Waiting for authentication reply"
|
141
|
+
auth_reply = recv(2)
|
142
|
+
if auth_reply[0] != 4 and auth_reply[0] != 5
|
143
|
+
raise SOCKSError.new("SOCKS version #{auth_reply[0]} not supported")
|
144
|
+
end
|
145
|
+
if auth_reply[1] != 0
|
146
|
+
raise SOCKSError.new("SOCKS authentication method #{auth_reply[1]} neither requested nor supported")
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Connect
|
151
|
+
def socks_connect(host, port)
|
152
|
+
Socksify::debug_debug "Sending destination address"
|
153
|
+
write "\005\001\000"
|
154
|
+
if host =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/ # to IPv4 address
|
155
|
+
write "\001" + [$1.to_i,
|
156
|
+
$2.to_i,
|
157
|
+
$3.to_i,
|
158
|
+
$4.to_i
|
159
|
+
].pack('CCCC')
|
160
|
+
elsif host =~ /^[:0-9a-f]+$/ # to IPv6 address
|
161
|
+
raise "TCP/IPv6 over SOCKS is not yet supported (inet_pton missing in Ruby & not supported by Tor"
|
162
|
+
write "\004"
|
163
|
+
else # to hostname
|
164
|
+
write "\003" + [host.size].pack('C') + host
|
165
|
+
end
|
166
|
+
write [port].pack('n')
|
167
|
+
|
168
|
+
socks_receive_reply
|
169
|
+
Socksify::debug_notice "Connected to #{host}:#{port} over SOCKS"
|
170
|
+
end
|
171
|
+
|
172
|
+
# returns [bind_addr: String, bind_port: Fixnum]
|
173
|
+
def socks_receive_reply
|
174
|
+
Socksify::debug_debug "Waiting for SOCKS reply"
|
175
|
+
connect_reply = recv(4)
|
176
|
+
if connect_reply[0] != 5
|
177
|
+
raise SOCKSError.new("SOCKS version #{connect_reply[0]} is not 5")
|
178
|
+
end
|
179
|
+
if connect_reply[1] != 0
|
180
|
+
raise SOCKSError.for_response_code(connect_reply[1])
|
181
|
+
end
|
182
|
+
Socksify::debug_debug "Waiting for bind_addr"
|
183
|
+
bind_addr_len = case connect_reply[3]
|
184
|
+
when 1
|
185
|
+
4
|
186
|
+
when 3
|
187
|
+
recv(1)[0]
|
188
|
+
when 4
|
189
|
+
16
|
190
|
+
else
|
191
|
+
raise SOCKSError.for_response_code(connect_reply[3])
|
192
|
+
end
|
193
|
+
bind_addr_s = recv(bind_addr_len)
|
194
|
+
bind_addr = case connect_reply[3]
|
195
|
+
when 1
|
196
|
+
"#{bind_addr_s[0]}.#{bind_addr_s[1]}.#{bind_addr_s[2]}.#{bind_addr_s[3]}"
|
197
|
+
when 3
|
198
|
+
bind_addr_s
|
199
|
+
when 4 # Untested!
|
200
|
+
i = 0
|
201
|
+
ip6 = ""
|
202
|
+
bind_addr_s.each_byte do |b|
|
203
|
+
if i > 0 and i % 2 == 0
|
204
|
+
ip6 += ":"
|
205
|
+
end
|
206
|
+
i += 1
|
207
|
+
|
208
|
+
ip6 += b.to_s(16).rjust(2, '0')
|
209
|
+
end
|
210
|
+
end
|
211
|
+
bind_port = recv(bind_addr_len + 2)
|
212
|
+
[bind_addr, bind_port.unpack('n')]
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
module Socksify
|
217
|
+
def self.resolve(host)
|
218
|
+
s = TCPSocket.new
|
219
|
+
|
220
|
+
begin
|
221
|
+
Socksify::debug_debug "Sending hostname to resolve: #{host}"
|
222
|
+
s.write "\005"
|
223
|
+
if host =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/ # to IPv4 address
|
224
|
+
s.write "\xF1\000\001" + [$1.to_i,
|
225
|
+
$2.to_i,
|
226
|
+
$3.to_i,
|
227
|
+
$4.to_i
|
228
|
+
].pack('CCCC')
|
229
|
+
elsif host =~ /^[:0-9a-f]+$/ # to IPv6 address
|
230
|
+
raise "TCP/IPv6 over SOCKS is not yet supported (inet_pton missing in Ruby & not supported by Tor"
|
231
|
+
s.write "\004"
|
232
|
+
else # to hostname
|
233
|
+
s.write "\xF0\000\003" + [host.size].pack('C') + host
|
234
|
+
end
|
235
|
+
s.write [0].pack('n') # Port
|
236
|
+
|
237
|
+
addr, port = s.socks_receive_reply
|
238
|
+
Socksify::debug_notice "Resolved #{host} as #{addr} over SOCKS"
|
239
|
+
addr
|
240
|
+
ensure
|
241
|
+
s.close
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: socksify
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephan Maka
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-03-15 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -25,13 +25,16 @@ extra_rdoc_files:
|
|
25
25
|
- COPYING
|
26
26
|
files:
|
27
27
|
- COPYING
|
28
|
-
- lib/socksify.rb
|
29
28
|
- lib/socksify_debug.rb
|
29
|
+
- lib/socksify.rb.orig
|
30
|
+
- lib/socksify.rb
|
30
31
|
- bin/socksify_ruby
|
31
32
|
- doc/index.css
|
32
33
|
- doc/index.html
|
33
|
-
has_rdoc:
|
34
|
+
has_rdoc: true
|
34
35
|
homepage: http://socksify.rubyforge.org/
|
36
|
+
licenses: []
|
37
|
+
|
35
38
|
post_install_message:
|
36
39
|
rdoc_options: []
|
37
40
|
|
@@ -52,9 +55,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
52
55
|
requirements: []
|
53
56
|
|
54
57
|
rubyforge_project: socksify
|
55
|
-
rubygems_version: 1.
|
58
|
+
rubygems_version: 1.3.5
|
56
59
|
signing_key:
|
57
|
-
specification_version:
|
60
|
+
specification_version: 3
|
58
61
|
summary: Redirect all TCPSockets through a SOCKS5 proxy
|
59
62
|
test_files: []
|
60
63
|
|