forwardmachine 0.0.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +13 -8
- data/examples/forwardmachine +138 -0
- data/forwardmachine.gemspec +3 -3
- data/lib/forwardmachine/forwarder.rb +10 -7
- data/lib/forwardmachine/forwarder_connection.rb +4 -4
- data/lib/forwardmachine/version.rb +1 -1
- metadata +7 -6
data/README.md
CHANGED
@@ -5,7 +5,9 @@ Port forwarding service configurable in runtime.
|
|
5
5
|
# How does it work?
|
6
6
|
|
7
7
|
ForwardMachine listens on TCP port for forward requests.
|
8
|
-
|
8
|
+
|
9
|
+
These requests are simple, they consist of host:port, e.g. host.example.com:3000.
|
10
|
+
|
9
11
|
As response, host and port where forwarding has been set up is returned.
|
10
12
|
|
11
13
|
## Installation
|
@@ -14,21 +16,24 @@ As response, host and port where forwarding has been set up is returned.
|
|
14
16
|
|
15
17
|
## Usage
|
16
18
|
|
17
|
-
|
19
|
+
Start forwarder for host proxy.example.com
|
18
20
|
|
19
21
|
$ forwardmachine --forwarder-host proxy.example.com --ports-range 8000..9000
|
20
22
|
|
21
|
-
|
23
|
+
Control server by default will listen on localhost:8899.
|
22
24
|
Connect to it and create a new forwarder (here we use nc tool).
|
23
|
-
Below we have created two ports forwards.
|
24
25
|
|
25
26
|
$ nc localhost 8899
|
26
|
-
|
27
|
-
|
27
|
+
internal1.example.com:7777
|
28
|
+
proxy.example.com:8000
|
29
|
+
|
30
|
+
proxy.example.com:8000 is forwarded to internal1.example.com:7777
|
28
31
|
|
29
32
|
$ nc localhost 8899
|
30
|
-
|
31
|
-
|
33
|
+
internal2.example.com:9999
|
34
|
+
proxy.example.com:8001
|
35
|
+
|
36
|
+
proxy.example.com:8001 is forwarded to internal2.example.com:9999
|
32
37
|
|
33
38
|
## Contributing
|
34
39
|
|
@@ -0,0 +1,138 @@
|
|
1
|
+
#! /bin/sh
|
2
|
+
### BEGIN INIT INFO
|
3
|
+
# Provides: forwardmachine
|
4
|
+
# Required-Start: $remote_fs $syslog
|
5
|
+
# Required-Stop: $remote_fs $syslog
|
6
|
+
# Default-Start: 2 3 4 5
|
7
|
+
# Default-Stop: 0 1 6
|
8
|
+
# Short-Description: Init script for forwardmachine
|
9
|
+
# Description: Init script for forwardmachine
|
10
|
+
#
|
11
|
+
### END INIT INFO
|
12
|
+
|
13
|
+
# Do NOT "set -e"
|
14
|
+
|
15
|
+
# PATH should only include /usr/* if it runs after the mountnfs.sh script
|
16
|
+
PATH=/usr/local/bin:/sbin:/usr/sbin:/bin:/usr/bin
|
17
|
+
DESC="Port forwarding service"
|
18
|
+
NAME=forwardmachine
|
19
|
+
DAEMON=`which forwardmachine`
|
20
|
+
DAEMON_ARGS="--forwarder-host proxy.example.com --ports-range 8000..9000 --log /var/log/forwardmachine/forwardmachine.log"
|
21
|
+
PIDFILE=/var/run/$NAME.pid
|
22
|
+
SCRIPTNAME=/etc/init.d/$NAME
|
23
|
+
|
24
|
+
# Load the VERBOSE setting and other rcS variables
|
25
|
+
. /lib/init/vars.sh
|
26
|
+
|
27
|
+
# Define LSB log_* functions.
|
28
|
+
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
|
29
|
+
# and status_of_proc is working.
|
30
|
+
. /lib/lsb/init-functions
|
31
|
+
|
32
|
+
#
|
33
|
+
# Function that starts the daemon/service
|
34
|
+
#
|
35
|
+
do_start()
|
36
|
+
{
|
37
|
+
# Return
|
38
|
+
# 0 if daemon has been started
|
39
|
+
# 1 if daemon was already running
|
40
|
+
# 2 if daemon could not be started
|
41
|
+
start-stop-daemon --start --quiet --background --chuid nobody --make-pidfile --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
|
42
|
+
|| return 1
|
43
|
+
start-stop-daemon --start --quiet --background --chuid nobody --make-pidfile --pidfile $PIDFILE --exec $DAEMON -- \
|
44
|
+
$DAEMON_ARGS \
|
45
|
+
|| return 2
|
46
|
+
# Add code here, if necessary, that waits for the process to be ready
|
47
|
+
# to handle requests from services started subsequently which depend
|
48
|
+
# on this one. As a last resort, sleep for some time.
|
49
|
+
}
|
50
|
+
|
51
|
+
#
|
52
|
+
# Function that stops the daemon/service
|
53
|
+
#
|
54
|
+
do_stop()
|
55
|
+
{
|
56
|
+
# Return
|
57
|
+
# 0 if daemon has been stopped
|
58
|
+
# 1 if daemon was already stopped
|
59
|
+
# 2 if daemon could not be stopped
|
60
|
+
# other if a failure occurred
|
61
|
+
start-stop-daemon --stop --quiet --chuid nobody --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
|
62
|
+
RETVAL="$?"
|
63
|
+
[ "$RETVAL" = 2 ] && return 2
|
64
|
+
# Wait for children to finish too if this is a daemon that forks
|
65
|
+
# and if the daemon is only ever run from this initscript.
|
66
|
+
# If the above conditions are not satisfied then add some other code
|
67
|
+
# that waits for the process to drop all resources that could be
|
68
|
+
# needed by services started subsequently. A last resort is to
|
69
|
+
# sleep for some time.
|
70
|
+
start-stop-daemon --stop --quiet --chuid nobody --oknodo --retry=0/30/KILL/5 --exec $DAEMON
|
71
|
+
[ "$?" = 2 ] && return 2
|
72
|
+
# Many daemons don't delete their pidfiles when they exit.
|
73
|
+
rm -f $PIDFILE
|
74
|
+
return "$RETVAL"
|
75
|
+
}
|
76
|
+
|
77
|
+
#
|
78
|
+
# Function that sends a SIGHUP to the daemon/service
|
79
|
+
#
|
80
|
+
do_reload() {
|
81
|
+
#
|
82
|
+
# If the daemon can reload its configuration without
|
83
|
+
# restarting (for example, when it is sent a SIGHUP),
|
84
|
+
# then implement that here.
|
85
|
+
#
|
86
|
+
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
|
87
|
+
return 0
|
88
|
+
}
|
89
|
+
|
90
|
+
case "$1" in
|
91
|
+
start)
|
92
|
+
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
|
93
|
+
do_start
|
94
|
+
case "$?" in
|
95
|
+
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
|
96
|
+
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
|
97
|
+
esac
|
98
|
+
;;
|
99
|
+
stop)
|
100
|
+
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
|
101
|
+
do_stop
|
102
|
+
case "$?" in
|
103
|
+
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
|
104
|
+
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
|
105
|
+
esac
|
106
|
+
;;
|
107
|
+
status)
|
108
|
+
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
|
109
|
+
;;
|
110
|
+
restart|force-reload)
|
111
|
+
#
|
112
|
+
# If the "reload" option is implemented then remove the
|
113
|
+
# 'force-reload' alias
|
114
|
+
#
|
115
|
+
log_daemon_msg "Restarting $DESC" "$NAME"
|
116
|
+
do_stop
|
117
|
+
case "$?" in
|
118
|
+
0|1)
|
119
|
+
do_start
|
120
|
+
case "$?" in
|
121
|
+
0) log_end_msg 0 ;;
|
122
|
+
1) log_end_msg 1 ;; # Old process is still running
|
123
|
+
*) log_end_msg 1 ;; # Failed to start
|
124
|
+
esac
|
125
|
+
;;
|
126
|
+
*)
|
127
|
+
# Failed to stop
|
128
|
+
log_end_msg 1
|
129
|
+
;;
|
130
|
+
esac
|
131
|
+
;;
|
132
|
+
*)
|
133
|
+
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
|
134
|
+
exit 3
|
135
|
+
;;
|
136
|
+
esac
|
137
|
+
|
138
|
+
:
|
data/forwardmachine.gemspec
CHANGED
@@ -17,9 +17,9 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.name = "forwardmachine"
|
18
18
|
gem.require_paths = ["lib"]
|
19
19
|
gem.version = ForwardMachine::VERSION
|
20
|
-
|
21
|
-
gem.add_runtime_dependency "eventmachine"
|
20
|
+
|
21
|
+
gem.add_runtime_dependency "eventmachine", "~> 0.12"
|
22
22
|
gem.add_runtime_dependency "em-logger"
|
23
|
-
|
23
|
+
|
24
24
|
gem.add_development_dependency "rspec"
|
25
25
|
end
|
@@ -3,7 +3,7 @@ module ForwardMachine
|
|
3
3
|
# ports pool. Each connection is handled by ForwarderConnection object
|
4
4
|
class Forwarder
|
5
5
|
# How long server will be open, waiting for the first connetion.
|
6
|
-
FIRST_USE_TIMEOUT =
|
6
|
+
FIRST_USE_TIMEOUT = 60
|
7
7
|
|
8
8
|
attr_reader :host, :destination, :ports_pool, :port, :connections
|
9
9
|
|
@@ -25,12 +25,15 @@ module ForwardMachine
|
|
25
25
|
# Public: Start forwarding server on given host and port taken from PortsPool.
|
26
26
|
# Returns: Socket address of the server in format "host:port" as String
|
27
27
|
def start
|
28
|
-
@server = EM.start_server(host, port, ForwarderConnection, destination, self)
|
28
|
+
@server = EM.start_server(host, port, ForwarderConnection, destination, self) do
|
29
29
|
@connections += 1
|
30
30
|
@inactivity_timer.cancel
|
31
|
-
|
32
|
-
@inactivity_timer = EM::PeriodicTimer.new(FIRST_USE_TIMEOUT)
|
33
|
-
|
31
|
+
end
|
32
|
+
@inactivity_timer = EM::PeriodicTimer.new(FIRST_USE_TIMEOUT) do
|
33
|
+
logger.info("Forwarder #{self} timed out after #{FIRST_USE_TIMEOUT} seconds")
|
34
|
+
stop
|
35
|
+
end
|
36
|
+
logger.info("Started forwarder #{self}")
|
34
37
|
socket_address
|
35
38
|
end
|
36
39
|
|
@@ -48,13 +51,13 @@ module ForwardMachine
|
|
48
51
|
end
|
49
52
|
|
50
53
|
def to_s
|
51
|
-
socket_address
|
54
|
+
"#{socket_address}->#{destination}"
|
52
55
|
end
|
53
56
|
|
54
57
|
private
|
55
58
|
|
56
59
|
def stop
|
57
|
-
logger.info("Stopped forwarder #{
|
60
|
+
logger.info("Stopped forwarder #{self}")
|
58
61
|
@inactivity_timer.cancel
|
59
62
|
EM.stop_server(@server)
|
60
63
|
ports_pool.release(port)
|
@@ -16,25 +16,25 @@ module ForwardMachine
|
|
16
16
|
# Internal: After client is connected to forwarder, open connection
|
17
17
|
# to destination host and port
|
18
18
|
def post_init
|
19
|
-
logger.info("Client #{peer} connected to forwarder #{@forwarder}
|
19
|
+
logger.info("Client #{peer} connected to forwarder #{@forwarder}")
|
20
20
|
EM.connect(@destination_host, @destination_port,
|
21
21
|
ForwardedConnection, self)
|
22
22
|
rescue RuntimeError => e
|
23
|
-
logger.error("Client #{peer} on #{@forwarder} couldn't be connected with
|
23
|
+
logger.error("Client #{peer} on #{@forwarder} couldn't be connected with destination")
|
24
24
|
close_connection
|
25
25
|
end
|
26
26
|
|
27
27
|
# Internal: After forwarder destination disconnected
|
28
28
|
# terminate forwarder connection
|
29
29
|
def proxy_target_unbound
|
30
|
-
logger.info("Destination
|
30
|
+
logger.info("Destination disconnected from forwarder #{@forwarder}")
|
31
31
|
close_connection
|
32
32
|
end
|
33
33
|
|
34
34
|
# Internal: After client disconnects from forwarder
|
35
35
|
# notify forwarder server about it.
|
36
36
|
def unbind
|
37
|
-
logger.info("Client #{peer} disconnected from forwarder #{@forwarder}
|
37
|
+
logger.info("Client #{peer} disconnected from forwarder #{@forwarder}")
|
38
38
|
@forwarder.forwarder_connection_closed
|
39
39
|
end
|
40
40
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: forwardmachine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,24 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-10-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: eventmachine
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: '0'
|
21
|
+
version: '0.12'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
none: false
|
26
26
|
requirements:
|
27
|
-
- -
|
27
|
+
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '0'
|
29
|
+
version: '0.12'
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: em-logger
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -75,6 +75,7 @@ files:
|
|
75
75
|
- README.md
|
76
76
|
- Rakefile
|
77
77
|
- bin/forwardmachine
|
78
|
+
- examples/forwardmachine
|
78
79
|
- forwardmachine.gemspec
|
79
80
|
- lib/forwardmachine.rb
|
80
81
|
- lib/forwardmachine/controller.rb
|