socksify 1.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/doc/index.html CHANGED
@@ -40,6 +40,7 @@
40
40
  </p>
41
41
 
42
42
  <h2>Installation</h2>
43
+ <pre>gem install socksify</pre>
43
44
 
44
45
  <h2>Usage</h2>
45
46
 
data/lib/socksify.rb ADDED
@@ -0,0 +1,237 @@
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
+
106
+ alias :initialize_tcp :initialize
107
+
108
+ # See http://tools.ietf.org/html/rfc1928
109
+ def initialize(host=nil, port=0, local_host="0.0.0.0", local_port=0)
110
+ socks_server = self.class.socks_server
111
+ socks_port = self.class.socks_port
112
+
113
+ if socks_server and socks_port
114
+ Socksify::debug_notice "Connecting to SOCKS server #{socks_server}:#{socks_port}"
115
+ initialize_tcp socks_server, socks_port
116
+
117
+ socks_authenticate
118
+
119
+ if host
120
+ socks_connect(host, port)
121
+ end
122
+ else
123
+ Socksify::debug_notice "Connecting directly to #{host}:#{port}"
124
+ initialize_tcp host, port, local_host, local_port
125
+ Socksify::debug_debug "Connected to #{host}:#{port}"
126
+ end
127
+ end
128
+
129
+ # Authentication
130
+ def socks_authenticate
131
+ Socksify::debug_debug "Sending no authentication"
132
+ write "\005\001\000"
133
+ Socksify::debug_debug "Waiting for authentication reply"
134
+ auth_reply = recv(2)
135
+ if auth_reply[0] != 4 and auth_reply[0] != 5
136
+ raise SOCKSError.new("SOCKS version #{auth_reply[0]} not supported")
137
+ end
138
+ if auth_reply[1] != 0
139
+ raise SOCKSError.new("SOCKS authentication method #{auth_reply[1]} neither requested nor supported")
140
+ end
141
+ end
142
+
143
+ # Connect
144
+ def socks_connect(host, port)
145
+ Socksify::debug_debug "Sending destination address"
146
+ write "\005\001\000"
147
+ if host =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/ # to IPv4 address
148
+ write "\001" + [$1.to_i,
149
+ $2.to_i,
150
+ $3.to_i,
151
+ $4.to_i
152
+ ].pack('CCCC')
153
+ elsif host =~ /^[:0-9a-f]+$/ # to IPv6 address
154
+ raise "TCP/IPv6 over SOCKS is not yet supported (inet_pton missing in Ruby & not supported by Tor"
155
+ write "\004"
156
+ else # to hostname
157
+ write "\003" + [host.size].pack('C') + host
158
+ end
159
+ write [port].pack('n')
160
+
161
+ socks_receive_reply
162
+ Socksify::debug_notice "Connected to #{host}:#{port} over SOCKS"
163
+ end
164
+
165
+ # returns [bind_addr: String, bind_port: Fixnum]
166
+ def socks_receive_reply
167
+ Socksify::debug_debug "Waiting for SOCKS reply"
168
+ connect_reply = recv(4)
169
+ if connect_reply[0] != 5
170
+ raise SOCKSError.new("SOCKS version #{connect_reply[0]} is not 5")
171
+ end
172
+ if connect_reply[1] != 0
173
+ raise SOCKSError.for_response_code(connect_reply[1])
174
+ end
175
+ Socksify::debug_debug "Waiting for bind_addr"
176
+ bind_addr_len = case connect_reply[3]
177
+ when 1
178
+ 4
179
+ when 3
180
+ recv(1)[0]
181
+ when 4
182
+ 16
183
+ else
184
+ raise SOCKSError.for_response_code(connect_reply[3])
185
+ end
186
+ bind_addr_s = recv(bind_addr_len)
187
+ bind_addr = case connect_reply[3]
188
+ when 1
189
+ "#{bind_addr_s[0]}.#{bind_addr_s[1]}.#{bind_addr_s[2]}.#{bind_addr_s[3]}"
190
+ when 3
191
+ bind_addr_s
192
+ when 4 # Untested!
193
+ i = 0
194
+ ip6 = ""
195
+ bind_addr_s.each_byte do |b|
196
+ if i > 0 and i % 2 == 0
197
+ ip6 += ":"
198
+ end
199
+ i += 1
200
+
201
+ ip6 += b.to_s(16).rjust(2, '0')
202
+ end
203
+ end
204
+ bind_port = recv(bind_addr_len + 2)
205
+ [bind_addr, bind_port.unpack('n')]
206
+ end
207
+ end
208
+
209
+ module Socksify
210
+ def self.resolve(host)
211
+ s = TCPSocket.new
212
+
213
+ begin
214
+ Socksify::debug_debug "Sending hostname to resolve: #{host}"
215
+ s.write "\005"
216
+ if host =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/ # to IPv4 address
217
+ s.write "\xF1\000\001" + [$1.to_i,
218
+ $2.to_i,
219
+ $3.to_i,
220
+ $4.to_i
221
+ ].pack('CCCC')
222
+ elsif host =~ /^[:0-9a-f]+$/ # to IPv6 address
223
+ raise "TCP/IPv6 over SOCKS is not yet supported (inet_pton missing in Ruby & not supported by Tor"
224
+ s.write "\004"
225
+ else # to hostname
226
+ s.write "\xF0\000\003" + [host.size].pack('C') + host
227
+ end
228
+ s.write [0].pack('n') # Port
229
+
230
+ addr, port = s.socks_receive_reply
231
+ Socksify::debug_notice "Resolved #{host} as #{addr} over SOCKS"
232
+ addr
233
+ ensure
234
+ s.close
235
+ end
236
+ end
237
+ end
@@ -0,0 +1,55 @@
1
+ class Color
2
+ class Reset
3
+ def self::to_s
4
+ "\e[0m\e[37m"
5
+ end
6
+ end
7
+
8
+ class Red < Color
9
+ def num; 31; end
10
+ end
11
+ class Green < Color
12
+ def num; 32; end
13
+ end
14
+ class Yellow < Color
15
+ def num; 33; end
16
+ end
17
+
18
+ def self::to_s
19
+ new.to_s
20
+ end
21
+
22
+ def to_s
23
+ "\e[1m\e[#{num}m"
24
+ end
25
+ end
26
+
27
+ module Socksify
28
+ def self.debug=(enabled)
29
+ @@debug = enabled
30
+ end
31
+
32
+ def self.debug_debug(str)
33
+ debug(Color::Green, str)
34
+ end
35
+
36
+ def self.debug_notice(str)
37
+ debug(Color::Yellow, str)
38
+ end
39
+
40
+ def self.debug_error(str)
41
+ debug(Color::Red, str)
42
+ end
43
+
44
+ private
45
+
46
+ def self.debug(color, str)
47
+ if defined? @@debug
48
+ puts "#{color}#{now_s}#{Color::Reset} #{str}"
49
+ end
50
+ end
51
+
52
+ def self.now_s
53
+ Time.now.strftime('%H:%M:%S')
54
+ end
55
+ 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.0"
4
+ version: 1.0.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: 2008-02-28 00:00:00 +01:00
12
+ date: 2008-03-10 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -25,6 +25,8 @@ extra_rdoc_files:
25
25
  - COPYING
26
26
  files:
27
27
  - COPYING
28
+ - lib/socksify.rb
29
+ - lib/socksify_debug.rb
28
30
  - bin/socksify_ruby
29
31
  - doc/index.css
30
32
  - doc/index.html