socksify 1.0 → 1.0.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 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