socksify 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/lib/socksify.rb +82 -45
  2. metadata +18 -6
  3. 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 "\005\001\000"
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" + [$1.to_i,
156
- $2.to_i,
157
- $3.to_i,
158
- $4.to_i
159
- ].pack('CCCC')
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
- write "\003" + [host.size].pack('C') + host
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
- connect_reply = recv(4)
176
- if connect_reply[0..0] != "\005"
177
- raise SOCKSError.new("SOCKS version #{connect_reply[0..0]} is not 5")
178
- end
179
- if connect_reply[1..1] != "\000"
180
- raise SOCKSError.for_response_code(connect_reply.bytes.to_a[1])
181
- end
182
- Socksify::debug_debug "Waiting for bind_addr"
183
- bind_addr_len = case connect_reply[3..3]
184
- when "\001"
185
- 4
186
- when "\003"
187
- recv(1).bytes.first
188
- when "\004"
189
- 16
190
- else
191
- raise SOCKSError.for_response_code(connect_reply.bytes.to_a[3])
192
- end
193
- bind_addr_s = recv(bind_addr_len)
194
- bind_addr = case connect_reply[3..3]
195
- when "\001"
196
- bind_addr_s.bytes.to_a.join('.')
197
- when "\003"
198
- bind_addr_s
199
- when "\004" # 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
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
- ip6 += b.to_s(16).rjust(2, '0')
238
+ ip6 += b.to_s(16).rjust(2, '0')
239
+ end
209
240
  end
210
- end
211
- bind_port = recv(bind_addr_len + 2)
212
- [bind_addr, bind_port.unpack('n')]
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
- version: 1.1.1
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-03-15 00:00:00 +01:00
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.5
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