socksify 1.4.0 → 1.4.1

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 +2 -2
  2. data/lib/socksify.rb.orig +244 -0
  3. metadata +4 -3
@@ -112,7 +112,7 @@ class TCPSocket
112
112
  @@socks_port = port
113
113
  end
114
114
  def self.socks_ignores
115
- @@socks_ignores ||= []
115
+ @@socks_ignores ||= %w(localhost)
116
116
  end
117
117
  def self.socks_ignores=(ignores)
118
118
  @@socks_ignores = ignores
@@ -125,7 +125,7 @@ class TCPSocket
125
125
  end
126
126
 
127
127
  def to_s
128
- "#{@peer_host} (via #{@socks_server}:#{@socks_port}"
128
+ "#{@peer_host} (via #{@socks_server}:#{@socks_port})"
129
129
  end
130
130
  alias_method :to_str, :to_s
131
131
  end
@@ -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
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 4
8
- - 0
9
- version: 1.4.0
8
+ - 1
9
+ version: 1.4.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Stephan Maka
@@ -18,7 +18,7 @@ autorequire:
18
18
  bindir: bin
19
19
  cert_chain: []
20
20
 
21
- date: 2011-03-31 00:00:00 +02:00
21
+ date: 2011-06-07 00:00:00 +02:00
22
22
  default_executable:
23
23
  dependencies: []
24
24
 
@@ -34,6 +34,7 @@ extra_rdoc_files:
34
34
  - COPYING
35
35
  files:
36
36
  - COPYING
37
+ - lib/socksify.rb.orig
37
38
  - lib/socksify/debug.rb
38
39
  - lib/socksify/http.rb
39
40
  - lib/socksify.rb