hydra5 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/.gitignore +5 -0
- data/.rspec +0 -0
- data/Gemfile +4 -0
- data/README.md +32 -0
- data/Rakefile +10 -0
- data/bin/hydra5 +36 -0
- data/hydra5.gemspec +24 -0
- data/lib/hydra5.rb +2 -0
- data/lib/hydra5/proxy.rb +73 -0
- data/lib/hydra5/version.rb +3 -0
- data/misc/hydra.png +0 -0
- metadata +91 -0
data/.gitignore
ADDED
data/.rspec
ADDED
File without changes
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# Hydra5: load-balanced (multi-headed) SOCKS5 proxy
|
2
|
+
|
3
|
+
Given a list of hosts hydra5 opens a pool of SOCKS5 tunnels and routes incoming requests via a random tunnel. In effect, hydra5 is a regular SOCKS5 proxy, except that each outbound request is automatically load-balanced.
|
4
|
+
|
5
|
+

|
6
|
+
|
7
|
+
Hydra uses SSH to establish the SOCKS5 tunnels and [em-proxy](https://github.com/igrigorik/em-proxy) to provide the transparent routing for any SOCKS5 compatible client.
|
8
|
+
|
9
|
+
## Getting started
|
10
|
+
|
11
|
+
```
|
12
|
+
$> gem install hydra5
|
13
|
+
$> hydra5 --listen 8080 --hosts host1,host2 --key ssh_key.pub --user name --verbose
|
14
|
+
```
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
c = Curl::Easy.new('http://jsonip.com')
|
18
|
+
c.proxy_url = 'localhost:8080'
|
19
|
+
c.proxy_type = Curl::CURLPROXY_SOCKS5
|
20
|
+
|
21
|
+
c.perform
|
22
|
+
c.body_str # => => {"ip":"72.52.131.237"}
|
23
|
+
|
24
|
+
c.perform
|
25
|
+
c.body_str # => => {"ip":"34.22.124.45"}
|
26
|
+
```
|
27
|
+
|
28
|
+
Of course, you can also convert hydra5 into a proper HTTP proxy by deploying [privoxy](http://www.privoxy.org/) or an equivalent tool in front.
|
29
|
+
|
30
|
+
## License
|
31
|
+
|
32
|
+
The MIT License - Copyright (c) 2011 Ilya Grigorik
|
data/Rakefile
ADDED
data/bin/hydra5
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
|
+
$LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
|
5
|
+
|
6
|
+
require 'hydra5'
|
7
|
+
require 'optparse'
|
8
|
+
|
9
|
+
ARGV << '--help' if ARGV.empty?
|
10
|
+
|
11
|
+
options = {}
|
12
|
+
OptionParser.new do |opts|
|
13
|
+
opts.banner = "Usage: hydra5 [options]"
|
14
|
+
|
15
|
+
opts.on("-l", "--listen PORT", Integer, "Port to listen on") do |v|
|
16
|
+
options[:listen] = v
|
17
|
+
end
|
18
|
+
|
19
|
+
opts.on("-h", "--hosts host1,host2,...", Array, "List of proxy hosts") do |v|
|
20
|
+
options[:hosts] = v
|
21
|
+
end
|
22
|
+
|
23
|
+
opts.on("-k", "--key path/to/key", String, "SSH key for the proxy hosts") do |v|
|
24
|
+
options[:key] = v
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on("-u", "--user username", String, "SSH username for the proxy hosts") do |v|
|
28
|
+
options[:user] = v
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.on("-v", "--verbose", "Run in debug mode") do |v|
|
32
|
+
options[:verbose] = v
|
33
|
+
end
|
34
|
+
end.parse!
|
35
|
+
|
36
|
+
Hydra5::Proxy.new(options).start!
|
data/hydra5.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "hydra5/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "hydra5"
|
7
|
+
s.version = Hydra5::VERSION
|
8
|
+
s.authors = ["Ilya Grigorik"]
|
9
|
+
s.email = ["ilya@igvita.com"]
|
10
|
+
s.homepage = "https://github.com/igrigorik/hydra5"
|
11
|
+
s.summary = "Load-balanced (multi-headed) SOCKS5 proxy"
|
12
|
+
s.description = s.summary
|
13
|
+
|
14
|
+
s.rubyforge_project = "hydra"
|
15
|
+
|
16
|
+
s.add_dependency "eventmachine", ">= 1.0.0.beta.4"
|
17
|
+
s.add_dependency "em-proxy"
|
18
|
+
s.add_development_dependency "rspec"
|
19
|
+
|
20
|
+
s.files = `git ls-files`.split("\n")
|
21
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
22
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
23
|
+
s.require_paths = ["lib"]
|
24
|
+
end
|
data/lib/hydra5.rb
ADDED
data/lib/hydra5/proxy.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'em-proxy'
|
2
|
+
|
3
|
+
module Hydra5
|
4
|
+
|
5
|
+
class Logger
|
6
|
+
[:info, :error].each do |m|
|
7
|
+
define_method m do |msg|
|
8
|
+
msg = msg.join(", ") if msg.is_a? Array
|
9
|
+
puts ["Hydra5", m, msg].join(" :: ")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Proxy
|
15
|
+
def initialize(options)
|
16
|
+
@listen = options.delete(:listen) || 8080
|
17
|
+
@user = options.delete(:user) || 'root'
|
18
|
+
@key = options.delete(:key)
|
19
|
+
@log = Logger.new
|
20
|
+
|
21
|
+
@hosts = options.delete(:hosts)
|
22
|
+
@hosts = @hosts.inject({}) {|h,k| h[@hosts.index(k)] = k; h}
|
23
|
+
|
24
|
+
@log.info "Establishing #{@hosts.size} SOCKS5 tunnels"
|
25
|
+
@@live = {}
|
26
|
+
@pids = []
|
27
|
+
end
|
28
|
+
|
29
|
+
def start!
|
30
|
+
EM.epoll
|
31
|
+
EM.run do
|
32
|
+
@hosts.each do |index, host|
|
33
|
+
tunnel = <<-CMD
|
34
|
+
ssh #{@user}@#{host} -D #{7000 + index} -NT
|
35
|
+
-o StrictHostKeyChecking=no
|
36
|
+
-o ServerAliveInterval=300
|
37
|
+
-o ConnectTimeout=5
|
38
|
+
-o ExitOnForwardFailure=yes
|
39
|
+
-i #{@key}
|
40
|
+
CMD
|
41
|
+
|
42
|
+
@pids << EM.system(tunnel) do |cmd, out|
|
43
|
+
@log.error ["Connection closed", out, @hosts[index]]
|
44
|
+
@@live.delete(index)
|
45
|
+
|
46
|
+
if @@live.empty?
|
47
|
+
@log.info "No live tunnels left, exiting"
|
48
|
+
exit
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
@@live[index] = host
|
53
|
+
end
|
54
|
+
|
55
|
+
at_exit do
|
56
|
+
pids = @pids.join(' ')
|
57
|
+
unless system("kill #{pids}")
|
58
|
+
@log.error "Could not kill all tunnels: #{pids}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
@log.info "Starting proxy on port #{@listen}"
|
63
|
+
|
64
|
+
::Proxy.start(:host => "0.0.0.0", :port => @listen, :debug => @verbose) do |conn|
|
65
|
+
tunnel = @@live.keys.shuffle.first
|
66
|
+
|
67
|
+
puts "routing connection to #{@@live[tunnel]}"
|
68
|
+
conn.server :srv, :host => "127.0.0.1", :port => 7000 + tunnel, :relay_client => true, :relay_server => true
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/misc/hydra.png
ADDED
Binary file
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hydra5
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ilya Grigorik
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-11-07 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: eventmachine
|
16
|
+
requirement: &2154144020 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.0.0.beta.4
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2154144020
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: em-proxy
|
27
|
+
requirement: &2154143600 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2154143600
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rspec
|
38
|
+
requirement: &2154143140 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2154143140
|
47
|
+
description: Load-balanced (multi-headed) SOCKS5 proxy
|
48
|
+
email:
|
49
|
+
- ilya@igvita.com
|
50
|
+
executables:
|
51
|
+
- hydra5
|
52
|
+
extensions: []
|
53
|
+
extra_rdoc_files: []
|
54
|
+
files:
|
55
|
+
- .gitignore
|
56
|
+
- .rspec
|
57
|
+
- Gemfile
|
58
|
+
- README.md
|
59
|
+
- Rakefile
|
60
|
+
- bin/hydra5
|
61
|
+
- hydra5.gemspec
|
62
|
+
- lib/hydra5.rb
|
63
|
+
- lib/hydra5/proxy.rb
|
64
|
+
- lib/hydra5/version.rb
|
65
|
+
- misc/hydra.png
|
66
|
+
homepage: https://github.com/igrigorik/hydra5
|
67
|
+
licenses: []
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options: []
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
80
|
+
requirements:
|
81
|
+
- - ! '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
requirements: []
|
85
|
+
rubyforge_project: hydra
|
86
|
+
rubygems_version: 1.8.5
|
87
|
+
signing_key:
|
88
|
+
specification_version: 3
|
89
|
+
summary: Load-balanced (multi-headed) SOCKS5 proxy
|
90
|
+
test_files: []
|
91
|
+
has_rdoc:
|