socksify 1.1.1 → 1.1.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/lib/socksify.rb +82 -45
- metadata +18 -6
- data/lib/socksify.rb.orig +0 -244
data/lib/socksify.rb
CHANGED
@@ -16,6 +16,7 @@
|
|
16
16
|
=end
|
17
17
|
|
18
18
|
require 'socket'
|
19
|
+
require 'resolv'
|
19
20
|
require 'socksify_debug'
|
20
21
|
|
21
22
|
class SOCKSError < RuntimeError
|
@@ -90,6 +91,14 @@ class SOCKSError < RuntimeError
|
|
90
91
|
end
|
91
92
|
|
92
93
|
class TCPSocket
|
94
|
+
@@socks_version ||= "5"
|
95
|
+
|
96
|
+
def self.socks_version
|
97
|
+
(@@socks_version == "4a" or @@socks_version == "4") ? "\004" : "\005"
|
98
|
+
end
|
99
|
+
def self.socks_version=(version)
|
100
|
+
@@socks_version = version.to_s
|
101
|
+
end
|
93
102
|
def self.socks_server
|
94
103
|
@@socks_server ||= nil
|
95
104
|
end
|
@@ -121,7 +130,7 @@ class TCPSocket
|
|
121
130
|
Socksify::debug_notice "Connecting to SOCKS server #{socks_server}:#{socks_port}"
|
122
131
|
initialize_tcp socks_server, socks_port
|
123
132
|
|
124
|
-
socks_authenticate
|
133
|
+
socks_authenticate unless @@socks_version =~ /^4/
|
125
134
|
|
126
135
|
if host
|
127
136
|
socks_connect(host, port)
|
@@ -150,20 +159,39 @@ class TCPSocket
|
|
150
159
|
# Connect
|
151
160
|
def socks_connect(host, port)
|
152
161
|
Socksify::debug_debug "Sending destination address"
|
153
|
-
write
|
162
|
+
write TCPSocket.socks_version
|
163
|
+
Socksify::debug_debug TCPSocket.socks_version.unpack "H*"
|
164
|
+
write "\001"
|
165
|
+
write "\000" if @@socks_version == "5"
|
166
|
+
write [port].pack('n') if @@socks_version =~ /^4/
|
167
|
+
|
168
|
+
if @@socks_version == "4"
|
169
|
+
host = Resolv::DNS.new.getaddress(host).to_s
|
170
|
+
end
|
171
|
+
Socksify::debug_debug host
|
154
172
|
if host =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/ # to IPv4 address
|
155
|
-
write "\001"
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
173
|
+
write "\001" if @@socks_version == "5"
|
174
|
+
_ip = [$1.to_i,
|
175
|
+
$2.to_i,
|
176
|
+
$3.to_i,
|
177
|
+
$4.to_i
|
178
|
+
].pack('CCCC')
|
179
|
+
write _ip
|
160
180
|
elsif host =~ /^[:0-9a-f]+$/ # to IPv6 address
|
161
181
|
raise "TCP/IPv6 over SOCKS is not yet supported (inet_pton missing in Ruby & not supported by Tor"
|
162
182
|
write "\004"
|
163
183
|
else # to hostname
|
164
|
-
|
184
|
+
if @@socks_version == "5"
|
185
|
+
write "\003" + [host.size].pack('C') + host
|
186
|
+
else
|
187
|
+
write "\000\000\000\001"
|
188
|
+
write "\007\000"
|
189
|
+
Socksify::debug_notice host
|
190
|
+
write host
|
191
|
+
write "\000"
|
192
|
+
end
|
165
193
|
end
|
166
|
-
write [port].pack('n')
|
194
|
+
write [port].pack('n') if @@socks_version == "5"
|
167
195
|
|
168
196
|
socks_receive_reply
|
169
197
|
Socksify::debug_notice "Connected to #{host}:#{port} over SOCKS"
|
@@ -172,44 +200,53 @@ class TCPSocket
|
|
172
200
|
# returns [bind_addr: String, bind_port: Fixnum]
|
173
201
|
def socks_receive_reply
|
174
202
|
Socksify::debug_debug "Waiting for SOCKS reply"
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
203
|
+
if @@socks_version == "5"
|
204
|
+
connect_reply = recv(4)
|
205
|
+
Socksify::debug_debug connect_reply.unpack "H*"
|
206
|
+
if connect_reply[0..0] != "\005"
|
207
|
+
raise SOCKSError.new("SOCKS version #{connect_reply[0..0]} is not 5")
|
208
|
+
end
|
209
|
+
if connect_reply[1..1] != "\000"
|
210
|
+
raise SOCKSError.for_response_code(connect_reply.bytes.to_a[1])
|
211
|
+
end
|
212
|
+
Socksify::debug_debug "Waiting for bind_addr"
|
213
|
+
bind_addr_len = case connect_reply[3..3]
|
214
|
+
when "\001"
|
215
|
+
4
|
216
|
+
when "\003"
|
217
|
+
recv(1).bytes.first
|
218
|
+
when "\004"
|
219
|
+
16
|
220
|
+
else
|
221
|
+
raise SOCKSError.for_response_code(connect_reply.bytes.to_a[3])
|
222
|
+
end
|
223
|
+
bind_addr_s = recv(bind_addr_len)
|
224
|
+
bind_addr = case connect_reply[3..3]
|
225
|
+
when "\001"
|
226
|
+
bind_addr_s.bytes.to_a.join('.')
|
227
|
+
when "\003"
|
228
|
+
bind_addr_s
|
229
|
+
when "\004" # Untested!
|
230
|
+
i = 0
|
231
|
+
ip6 = ""
|
232
|
+
bind_addr_s.each_byte do |b|
|
233
|
+
if i > 0 and i % 2 == 0
|
234
|
+
ip6 += ":"
|
235
|
+
end
|
236
|
+
i += 1
|
207
237
|
|
208
|
-
|
238
|
+
ip6 += b.to_s(16).rjust(2, '0')
|
239
|
+
end
|
209
240
|
end
|
210
|
-
|
211
|
-
|
212
|
-
|
241
|
+
bind_port = recv(bind_addr_len + 2)
|
242
|
+
[bind_addr, bind_port.unpack('n')]
|
243
|
+
else
|
244
|
+
connect_reply = recv(8)
|
245
|
+
unless connect_reply[0] == "\000" and connect_reply[1] == "\x5A"
|
246
|
+
Socksify::debug_debug connect_reply.unpack 'H'
|
247
|
+
raise SOCKSError.new("Failed while connecting througth socks")
|
248
|
+
end
|
249
|
+
end
|
213
250
|
end
|
214
251
|
end
|
215
252
|
|
metadata
CHANGED
@@ -1,15 +1,22 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: socksify
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 1
|
9
|
+
- 2
|
10
|
+
version: 1.1.2
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Stephan Maka
|
14
|
+
- Andrey Kouznetsov
|
8
15
|
autorequire:
|
9
16
|
bindir: bin
|
10
17
|
cert_chain: []
|
11
18
|
|
12
|
-
date: 2010-
|
19
|
+
date: 2010-10-20 00:00:00 +02:00
|
13
20
|
default_executable:
|
14
21
|
dependencies: []
|
15
22
|
|
@@ -26,7 +33,6 @@ extra_rdoc_files:
|
|
26
33
|
files:
|
27
34
|
- COPYING
|
28
35
|
- lib/socksify_debug.rb
|
29
|
-
- lib/socksify.rb.orig
|
30
36
|
- lib/socksify.rb
|
31
37
|
- bin/socksify_ruby
|
32
38
|
- doc/index.css
|
@@ -41,21 +47,27 @@ rdoc_options: []
|
|
41
47
|
require_paths:
|
42
48
|
- lib
|
43
49
|
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
44
51
|
requirements:
|
45
52
|
- - ">="
|
46
53
|
- !ruby/object:Gem::Version
|
54
|
+
hash: 3
|
55
|
+
segments:
|
56
|
+
- 0
|
47
57
|
version: "0"
|
48
|
-
version:
|
49
58
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
50
60
|
requirements:
|
51
61
|
- - ">="
|
52
62
|
- !ruby/object:Gem::Version
|
63
|
+
hash: 3
|
64
|
+
segments:
|
65
|
+
- 0
|
53
66
|
version: "0"
|
54
|
-
version:
|
55
67
|
requirements: []
|
56
68
|
|
57
69
|
rubyforge_project: socksify
|
58
|
-
rubygems_version: 1.3.
|
70
|
+
rubygems_version: 1.3.7
|
59
71
|
signing_key:
|
60
72
|
specification_version: 3
|
61
73
|
summary: Redirect all TCPSockets through a SOCKS5 proxy
|
data/lib/socksify.rb.orig
DELETED
@@ -1,244 +0,0 @@
|
|
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
|