socks_handler 0.1.0

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/sig/defs.rbs ADDED
@@ -0,0 +1,509 @@
1
+ # This file was generated by "rake generate_rbs"
2
+
3
+ # An implementation of https://www.ietf.org/rfc/rfc1928.txt
4
+ # @private
5
+ module SocksHandler
6
+ PROTOCOL_VERSION: Integer
7
+ VERSION: String
8
+
9
+ # _@param_ `socket`
10
+ #
11
+ # _@param_ `username`
12
+ #
13
+ # _@param_ `password`
14
+ def negotiate: ((Socket | TCPSocket) socket, String? username, String? password) -> void
15
+
16
+ # _@param_ `socket`
17
+ #
18
+ # _@param_ `username`
19
+ #
20
+ # _@return_ — code of authentication method
21
+ def choose_auth_method: ((Socket | TCPSocket) socket, String? username) -> Integer
22
+
23
+ # _@param_ `socket`
24
+ #
25
+ # _@param_ `command`
26
+ #
27
+ # _@param_ `remote_host`
28
+ #
29
+ # _@param_ `remote_port` — a port number or service name such as "http"
30
+ #
31
+ # _@return_ — an array of [bound_address, bound_port]
32
+ def send_details: (
33
+ (Socket | TCPSocket) socket,
34
+ Integer command,
35
+ String remote_host,
36
+ (Integer | String) remote_port
37
+ ) -> [String, Integer]
38
+
39
+ # _@param_ `remote_host`
40
+ #
41
+ # _@param_ `remote_port`
42
+ def build_destination_packets: (String remote_host, (Integer | String) remote_port) -> String
43
+
44
+ # _@param_ `io`
45
+ #
46
+ # _@return_ — an array of [bound_address, bound_port]
47
+ def process_reply: ((TCPSocket | Socket | StringIO) io) -> [String, Integer]
48
+
49
+ class TCP
50
+ extend SocksHandler
51
+
52
+ # Socksifies all TCP connections created by TCPSocket.new or Socket.tcp
53
+ #
54
+ # _@param_ `rules` — socksify a socket according to the first rule whose remote host patterns match the remote host
55
+ #
56
+ # ```ruby
57
+ # SocksHandler::TCP.socksify([
58
+ # # Access 127.0.0.1, ::1 or hosts that end in ".local" directly
59
+ # SocksHandler::DirectAccessRule.new(host_patterns: %w[127.0.0.1 ::1] + [/\.local\z/]),
60
+ #
61
+ # # Access hosts that end in ".ap-northeast-1.compute.internal" through 127.0.0.1:1080
62
+ # SocksHandler::ProxyAccessRule.new(
63
+ # host_patterns: [/\.ap-northeast-1\.compute\.internal\z/],
64
+ # socks_server: "127.0.0.1:1080",
65
+ # ),
66
+ #
67
+ # # Access hosts that end in ".ec2.internal" through 127.0.0.1:1081
68
+ # SocksHandler::ProxyAccessRule.new(
69
+ # host_patterns: [/\.ec2\.internal\z/],
70
+ # socks_server: "127.0.0.1:1081",
71
+ # ),
72
+ #
73
+ # # Access others hosts through 127.0.0.1:1082 with username/password auth
74
+ # SocksHandler::ProxyAccessRule.new(
75
+ # host_patterns: [//],
76
+ # socks_server: "127.0.0.1:1082",
77
+ # username: "user",
78
+ # password: ENV["SOCKS_SERVER_PASSWORD"],
79
+ # ),
80
+ # ])
81
+ # ```
82
+ def self.socksify: (::Array[(DirectAccessRule | ProxyAccessRule)] rules) -> void
83
+
84
+ def self.desocksify: () -> void
85
+
86
+ # _@param_ `host` — a domain name or IP address of a remote host
87
+ def self.find_rule: (String host) -> (DirectAccessRule | ProxyAccessRule)?
88
+
89
+ # Connects a host through a socks server
90
+ #
91
+ # _@param_ `socket` — a socket that has connected to a socks server
92
+ #
93
+ # _@param_ `remote_host`
94
+ #
95
+ # _@param_ `remote_port` — a port number or service name such as "http"
96
+ #
97
+ # _@param_ `username`
98
+ #
99
+ # _@param_ `password`
100
+ #
101
+ # ```ruby
102
+ # socket = TCPSocket.new("127.0.0.1", 1080) # or Socket.tcp("127.0.0.1", 1080)
103
+ # # "nginx" is an HTTP server only the socks server can access
104
+ # SocksHandler::TCP.establish_connection(socket, "nginx", 80)
105
+ #
106
+ # socket.write(<<~REQUEST.gsub("\n", "\r\n"))
107
+ # HEAD / HTTP/1.1
108
+ # Host: nginx
109
+ #
110
+ # REQUEST
111
+ # puts socket.gets #=> HTTP/1.1 200 OK
112
+ # ```
113
+ def self.establish_connection: (
114
+ (Socket | TCPSocket) socket,
115
+ String remote_host,
116
+ (Integer | String) remote_port,
117
+ ?String? username,
118
+ ?String? password
119
+ ) -> void
120
+
121
+ def self.rules: () -> ::Array[(DirectAccessRule | ProxyAccessRule)]
122
+
123
+ # _@param_ `socket`
124
+ #
125
+ # _@param_ `username`
126
+ #
127
+ # _@param_ `password`
128
+ def self.negotiate: ((Socket | TCPSocket) socket, String? username, String? password) -> void
129
+
130
+ # _@param_ `socket`
131
+ #
132
+ # _@param_ `username`
133
+ #
134
+ # _@return_ — code of authentication method
135
+ def self.choose_auth_method: ((Socket | TCPSocket) socket, String? username) -> Integer
136
+
137
+ # _@param_ `socket`
138
+ #
139
+ # _@param_ `command`
140
+ #
141
+ # _@param_ `remote_host`
142
+ #
143
+ # _@param_ `remote_port` — a port number or service name such as "http"
144
+ #
145
+ # _@return_ — an array of [bound_address, bound_port]
146
+ def self.send_details: (
147
+ (Socket | TCPSocket) socket,
148
+ Integer command,
149
+ String remote_host,
150
+ (Integer | String) remote_port
151
+ ) -> [String, Integer]
152
+
153
+ # _@param_ `remote_host`
154
+ #
155
+ # _@param_ `remote_port`
156
+ def self.build_destination_packets: (String remote_host, (Integer | String) remote_port) -> String
157
+
158
+ # _@param_ `io`
159
+ #
160
+ # _@return_ — an array of [bound_address, bound_port]
161
+ def self.process_reply: ((TCPSocket | Socket | StringIO) io) -> [String, Integer]
162
+ end
163
+
164
+ class UDP
165
+ extend SocksHandler
166
+
167
+ # Associates a TCP socket with a UDP connection
168
+ #
169
+ # _@param_ `socket` — a socket that has connected to a socks server
170
+ #
171
+ # _@param_ `bind_host` — host for UDPSocket#bind
172
+ #
173
+ # _@param_ `bind_port` — port for UDPSocket#bind
174
+ #
175
+ # _@param_ `username`
176
+ #
177
+ # _@param_ `password`
178
+ #
179
+ # ```ruby
180
+ # tcp_socket = TCPSocket.new("127.0.0.1", 1080) # or Socket.tcp("127.0.0.1", 1080)
181
+ # udp_socket = SocksHandler::UDP.associate_udp(tcp_socket, "0.0.0.0", 0)
182
+ #
183
+ # "echo" is a UDP echo server that only the socks server can access
184
+ # udp_socket.send("hello", 0, "echo", 7)
185
+ # puts udp_socket.gets #=> hello
186
+ # ```
187
+ def self.associate_udp: (
188
+ (Socket | TCPSocket) socket,
189
+ String bind_host,
190
+ (Integer | String) bind_port,
191
+ ?String? username,
192
+ ?String? password
193
+ ) -> SocksHandler::UDPSocket
194
+
195
+ # _@param_ `socket`
196
+ #
197
+ # _@param_ `username`
198
+ #
199
+ # _@param_ `password`
200
+ def self.negotiate: ((Socket | TCPSocket) socket, String? username, String? password) -> void
201
+
202
+ # _@param_ `socket`
203
+ #
204
+ # _@param_ `username`
205
+ #
206
+ # _@return_ — code of authentication method
207
+ def self.choose_auth_method: ((Socket | TCPSocket) socket, String? username) -> Integer
208
+
209
+ # _@param_ `socket`
210
+ #
211
+ # _@param_ `command`
212
+ #
213
+ # _@param_ `remote_host`
214
+ #
215
+ # _@param_ `remote_port` — a port number or service name such as "http"
216
+ #
217
+ # _@return_ — an array of [bound_address, bound_port]
218
+ def self.send_details: (
219
+ (Socket | TCPSocket) socket,
220
+ Integer command,
221
+ String remote_host,
222
+ (Integer | String) remote_port
223
+ ) -> [String, Integer]
224
+
225
+ # _@param_ `remote_host`
226
+ #
227
+ # _@param_ `remote_port`
228
+ def self.build_destination_packets: (String remote_host, (Integer | String) remote_port) -> String
229
+
230
+ # _@param_ `io`
231
+ #
232
+ # _@return_ — an array of [bound_address, bound_port]
233
+ def self.process_reply: ((TCPSocket | Socket | StringIO) io) -> [String, Integer]
234
+ end
235
+
236
+ # @!attribute [r] host
237
+ # @return [String, nil]
238
+ # @!attribute [r] port
239
+ # @return [Integer, nil]
240
+ # @!attribute [r] username
241
+ # @return [String, nil]
242
+ # @!attribute [r] password
243
+ # @return [String, nil]
244
+ # @!attribute [r] host_patterns
245
+ # @return [Array<String, Regexp>]
246
+ class Rule
247
+ # sord omit - no YARD type given for "**kwargs", using untyped
248
+ def self.new: (**untyped kwargs) -> Rule
249
+
250
+ # _@param_ `host_patterns`
251
+ #
252
+ # _@param_ `host`
253
+ #
254
+ # _@param_ `port`
255
+ #
256
+ # _@param_ `username`
257
+ #
258
+ # _@param_ `password`
259
+ def initialize: (
260
+ host_patterns: ::Array[(String | Regexp)],
261
+ ?host: String?,
262
+ ?port: Integer?,
263
+ ?username: String?,
264
+ ?password: String?
265
+ ) -> void
266
+
267
+ def direct: () -> bool
268
+
269
+ # _@param_ `remote_host`
270
+ def match?: (String remote_host) -> bool
271
+
272
+ # _@param_ `value`
273
+ def convert_regexps: (::Array[(String | Regexp)] value) -> ::Array[Regexp]
274
+
275
+ attr_reader host: String?
276
+
277
+ attr_reader port: Integer?
278
+
279
+ attr_reader username: String?
280
+
281
+ attr_reader password: String?
282
+
283
+ attr_accessor host_patterns: ::Array[(String | Regexp)]
284
+ end
285
+
286
+ class UnsupportedProtocol < StandardError
287
+ end
288
+
289
+ class NoAcceptableMethods < StandardError
290
+ end
291
+
292
+ class AuthenticationFailure < StandardError
293
+ end
294
+
295
+ class RelayRequestFailure < StandardError
296
+ # _@param_ `code`
297
+ def initialize: (Integer code) -> void
298
+ end
299
+
300
+ module Command
301
+ CONNECT: Integer
302
+ BIND: Integer
303
+ UDP_ASSOCIATE: Integer
304
+ end
305
+
306
+ class UDPSocket < ::UDPSocket
307
+ include SocksHandler
308
+ MAX_REPLY_SIZE: Integer
309
+
310
+ # _@param_ `host`
311
+ #
312
+ # _@param_ `port`
313
+ def connect_socks_server: (String host, Integer port) -> Integer
314
+
315
+ # _@param_ `host`
316
+ #
317
+ # _@param_ `port`
318
+ #
319
+ # _@see_ `UDPSocket#connect`
320
+ def connect: (String host, Integer port) -> Integer
321
+
322
+ # _@param_ `maxlen`
323
+ #
324
+ # _@param_ `flags`
325
+ #
326
+ # _@see_ `UDPSocket#recv`
327
+ def recv: (Integer maxlen, ?Integer flags) -> String
328
+
329
+ # _@param_ `maxlen`
330
+ #
331
+ # _@param_ `maxlen`
332
+ #
333
+ # _@param_ `flags`
334
+ def recvfrom_socks_server: (Integer maxlen, ?Integer flags) -> [String, [String, Integer, String, String]]
335
+
336
+ # _@param_ `maxlen`
337
+ #
338
+ # _@param_ `flags`
339
+ #
340
+ # _@see_ `UDPSocket#recvfrom)`
341
+ def recvfrom: (Integer maxlen, ?Integer flags) -> [String, [String, Integer, String, String]]
342
+
343
+ # _@param_ `maxlen`
344
+ #
345
+ # _@param_ `flags`
346
+ def recvfrom_socks_server_nonblock: (Integer maxlen, ?Integer flags) -> [String, [String, Integer, String, String]]
347
+
348
+ # _@param_ `maxlen`
349
+ #
350
+ # _@param_ `flags`
351
+ #
352
+ # _@see_ `UDPSocket#recvfrom_nonblock`
353
+ def recvfrom_nonblock: (Integer maxlen, ?Integer flags) -> [String, [String, Integer, String, String]]
354
+
355
+ # _@param_ `mesg`
356
+ #
357
+ # _@param_ `flags`
358
+ #
359
+ # _@param_ `host`
360
+ #
361
+ # _@param_ `port`
362
+ #
363
+ # _@see_ `UDPSocket#send`
364
+ def send: (
365
+ String mesg,
366
+ Integer flags,
367
+ ?String? host,
368
+ ?(Integer | String)? port
369
+ ) -> Integer
370
+
371
+ # _@param_ `method`
372
+ #
373
+ # _@param_ `maxlen`
374
+ #
375
+ # _@param_ `flags`
376
+ def recvfrom_via: (Method method, Integer maxlen, Integer flags) -> [String, [String, Integer, String, String]]
377
+
378
+ # _@param_ `socket`
379
+ #
380
+ # _@param_ `username`
381
+ #
382
+ # _@param_ `password`
383
+ def negotiate: ((Socket | TCPSocket) socket, String? username, String? password) -> void
384
+
385
+ # _@param_ `socket`
386
+ #
387
+ # _@param_ `username`
388
+ #
389
+ # _@return_ — code of authentication method
390
+ def choose_auth_method: ((Socket | TCPSocket) socket, String? username) -> Integer
391
+
392
+ # _@param_ `socket`
393
+ #
394
+ # _@param_ `command`
395
+ #
396
+ # _@param_ `remote_host`
397
+ #
398
+ # _@param_ `remote_port` — a port number or service name such as "http"
399
+ #
400
+ # _@return_ — an array of [bound_address, bound_port]
401
+ def send_details: (
402
+ (Socket | TCPSocket) socket,
403
+ Integer command,
404
+ String remote_host,
405
+ (Integer | String) remote_port
406
+ ) -> [String, Integer]
407
+
408
+ # _@param_ `remote_host`
409
+ #
410
+ # _@param_ `remote_port`
411
+ def build_destination_packets: (String remote_host, (Integer | String) remote_port) -> String
412
+
413
+ # _@param_ `io`
414
+ #
415
+ # _@return_ — an array of [bound_address, bound_port]
416
+ def process_reply: ((TCPSocket | Socket | StringIO) io) -> [String, Integer]
417
+ end
418
+
419
+ module AddressType
420
+ IPV4: Integer
421
+ DOMAINNAME: Integer
422
+ IPV6: Integer
423
+ end
424
+
425
+ module SocketSocksify
426
+ # _@param_ `remote_host`
427
+ #
428
+ # _@param_ `remote_port`
429
+ #
430
+ # _@param_ `local_host`
431
+ #
432
+ # _@param_ `local_port`
433
+ #
434
+ # _@param_ `connect_timeout`
435
+ #
436
+ # _@param_ `resolv_timeout`
437
+ def tcp: (
438
+ String remote_host,
439
+ (Integer | String) remote_port,
440
+ ?String? local_host,
441
+ ?(Integer | String)? local_port,
442
+ ?connect_timeout: (Integer | Float)?,
443
+ ?resolv_timeout: (Integer | Float)?
444
+ ) -> Socket
445
+ end
446
+
447
+ class ProxyAccessRule < SocksHandler::Rule
448
+ # _@param_ `host_patterns`
449
+ #
450
+ # _@param_ `socks_server` — a string in the format "<host>:<port>"
451
+ #
452
+ # _@param_ `username`
453
+ #
454
+ # _@param_ `password`
455
+ def initialize: (
456
+ host_patterns: ::Array[(String | Regexp)],
457
+ socks_server: String,
458
+ ?username: String?,
459
+ ?password: String?
460
+ ) -> void
461
+
462
+ def direct: () -> bool
463
+ end
464
+
465
+ class DirectAccessRule < SocksHandler::Rule
466
+ # _@param_ `host_patterns`
467
+ def initialize: (host_patterns: ::Array[(String | Regexp)]) -> void
468
+
469
+ def direct: () -> bool
470
+ end
471
+
472
+ module TCPSocketSocksify
473
+ # _@param_ `remote_host`
474
+ #
475
+ # _@param_ `remote_port`
476
+ #
477
+ # _@param_ `local_host`
478
+ #
479
+ # _@param_ `local_port`
480
+ #
481
+ # _@param_ `connect_timeout`
482
+ def initialize: (
483
+ String remote_host,
484
+ (Integer | String) remote_port,
485
+ ?String? local_host,
486
+ ?(Integer | String)? local_port,
487
+ ?connect_timeout: (Integer | Float)?
488
+ ) -> void
489
+ end
490
+
491
+ module AuthenticationMethod
492
+ NONE: Integer
493
+ GSSAPI: Integer
494
+ USERNAME_PASSWORD: Integer
495
+ end
496
+
497
+ # An implementation of https://www.ietf.org/rfc/rfc1929.txt
498
+ class UsernamePasswordAuthenticator
499
+ SUBNEGOTIATION_VERSION: Integer
500
+
501
+ # _@param_ `username`
502
+ #
503
+ # _@param_ `password`
504
+ def initialize: (String username, String password) -> void
505
+
506
+ # _@param_ `socket`
507
+ def authenticate: ((Socket | TCPSocket) socket) -> void
508
+ end
509
+ end
@@ -0,0 +1,5 @@
1
+ module SocksHandler
2
+ class Rule
3
+ @remote_host_pattern_regex: Regexp
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ module SocksHandler
2
+ class UsernamePasswordAuthenticator
3
+ @username: String
4
+ @password: String
5
+ end
6
+ end
data/sig/socket.rbs ADDED
@@ -0,0 +1,4 @@
1
+ # Workaround for the error "RBS::NoTypeFoundError: Could not find Socket/TCPSocket/UDPSocket"
2
+ class Socket end
3
+ class TCPSocket end
4
+ class UDPSocket end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/socks_handler/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "socks_handler"
7
+ spec.version = SocksHandler::VERSION
8
+ spec.authors = ["abicky"]
9
+ spec.email = ["takeshi.arabiki@gmail.com"]
10
+
11
+ spec.summary = "A flexible socksifier for sockets created by TCPSocket.new, Socket.tcp or UDPSocket.new"
12
+ spec.description = <<~DESC
13
+ SocksHandler is a flexible socksifier for sockets created by `TCPSocket.new`, `Socket.tcp` or UDPSocket.new that solves the following issues:
14
+ 1) `SOCKSSocket` is not easy to use, 2) Famous socksifiers such as socksify and proxychains4 don't support rules using domain names.
15
+ DESC
16
+ spec.homepage = "https://github.com/abicky/socks_handler"
17
+ spec.license = "MIT"
18
+ spec.required_ruby_version = ">= 3.0.0"
19
+
20
+ spec.metadata["homepage_uri"] = spec.homepage
21
+ spec.metadata["source_code_uri"] = spec.homepage
22
+
23
+ spec.files = Dir.chdir(__dir__) do
24
+ `git ls-files -z`.split("\x0").reject do |f|
25
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
26
+ end
27
+ end
28
+ spec.bindir = "exe"
29
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib"]
31
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: socks_handler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - abicky
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-08-30 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: |
14
+ SocksHandler is a flexible socksifier for sockets created by `TCPSocket.new`, `Socket.tcp` or UDPSocket.new that solves the following issues:
15
+ 1) `SOCKSSocket` is not easy to use, 2) Famous socksifiers such as socksify and proxychains4 don't support rules using domain names.
16
+ email:
17
+ - takeshi.arabiki@gmail.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - ".rspec"
23
+ - Gemfile
24
+ - LICENSE.txt
25
+ - README.md
26
+ - Rakefile
27
+ - docker-compose.yml
28
+ - lib/socks_handler.rb
29
+ - lib/socks_handler/address_type.rb
30
+ - lib/socks_handler/authentication_method.rb
31
+ - lib/socks_handler/command.rb
32
+ - lib/socks_handler/direct_access_rule.rb
33
+ - lib/socks_handler/errors.rb
34
+ - lib/socks_handler/proxy_access_rule.rb
35
+ - lib/socks_handler/rule.rb
36
+ - lib/socks_handler/socket_socksify.rb
37
+ - lib/socks_handler/tcp.rb
38
+ - lib/socks_handler/tcpsocket_socksify.rb
39
+ - lib/socks_handler/udp.rb
40
+ - lib/socks_handler/udpsocket.rb
41
+ - lib/socks_handler/udpsocket_socksify.rb
42
+ - lib/socks_handler/username_password_authenticator.rb
43
+ - lib/socks_handler/version.rb
44
+ - sig/defs.rbs
45
+ - sig/lib/socks_handler/rule.rbs
46
+ - sig/lib/socks_handler/username_password_authenticator.rbs
47
+ - sig/socket.rbs
48
+ - socks_handler.gemspec
49
+ homepage: https://github.com/abicky/socks_handler
50
+ licenses:
51
+ - MIT
52
+ metadata:
53
+ homepage_uri: https://github.com/abicky/socks_handler
54
+ source_code_uri: https://github.com/abicky/socks_handler
55
+ post_install_message:
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 3.0.0
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ requirements: []
70
+ rubygems_version: 3.4.10
71
+ signing_key:
72
+ specification_version: 4
73
+ summary: A flexible socksifier for sockets created by TCPSocket.new, Socket.tcp or
74
+ UDPSocket.new
75
+ test_files: []