1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
|
#!/usr/bin/env python
"""
A Port Forwarding Example
This example demonstrates slightly more complex features and behaviors
implementing a TCP/UDP Port Forwarder of network traffic. This can be used
as a simple tool to forward traffic from one port to another.
Example:
-------
./portforward.py 0.0.0.0:2222 127.0.0.1:22
This example also has support for daemonizing the process into the background.
"""
from optparse import OptionParser
from uuid import uuid4 as uuid
from circuits import Component, Debugger, handler
from circuits.app import Daemon
from circuits.net.events import close, connect, write
from circuits.net.sockets import TCPClient, TCPServer
__version__ = '0.2'
USAGE = '%prog [options] <srcaddr:srcport> <destaddr:destport>'
VERSION = '%prog v' + __version__
def parse_options():
parser = OptionParser(usage=USAGE, version=VERSION)
parser.add_option(
'-d',
'--daemon',
action='store_true',
default=False,
dest='daemon',
help='Enable daemon mode (fork into the background)',
)
parser.add_option(
'',
'--debug',
action='store_true',
default=False,
dest='debug',
help='Enable debug mode (verbose event output)',
)
opts, args = parser.parse_args()
if len(args) < 2:
parser.print_help()
raise SystemExit(1)
return opts, args
def _on_target_disconnected(self, event):
"""
Disconnected Event Handler
This unbound function will be later added as an event handler to a
dynamically created and registered client instance and used to process
Disconnected events of a connected client.
"""
channel = event.channels[0]
sock = self._sockets[channel]
self.fire(close(sock), 'source')
del self._sockets[channel]
del self._clients[sock]
def _on_target_ready(self, component):
"""
Ready Event Handler
This unbound function will be later added as an event handler to a
dynamically created and registered client instance and used to process
Ready events of a registered client.
"""
self.fire(connect(*self._target, secure=self._secure), component.channel)
def _on_target_read(self, event, data):
"""
Read Event Handler
This unbound function will be later added as an event handler to a
dynamically created and registered client instance and used to process
Read events of a connected client.
"""
sock = self._sockets[event.channels[0]]
self.fire(write(sock, data), 'source')
class PortForwarder(Component):
def init(self, source, target, secure=False):
self._source = source
self._target = target
self._secure = secure
self._clients = {}
self._sockets = {}
# Setup our components and register them.
server = TCPServer(self._source, secure=self._secure, channel='source')
server.register(self)
@handler('connect', channel='source')
def _on_source_connect(self, sock, host, port):
"""
Explicitly defined connect Event Handler
This evens is triggered by the underlying TCPServer Component when
a new client connection has been made.
Here we dynamically create a Client instance, registere it and add
custom event handlers to handle the events of the newly created
client. The client is registered with a unique channel per connection.
"""
bind = 0
channel = uuid()
client = TCPClient(bind, channel=channel)
client.register(self)
self.addHandler(
handler('disconnected', channel=channel)(_on_target_disconnected),
)
self.addHandler(
handler('ready', channel=channel)(_on_target_ready),
)
self.addHandler(
handler('read', channel=channel)(_on_target_read),
)
self._clients[sock] = client
self._sockets[client.channel] = sock
@handler('read', channel='source')
def _on_source_read(self, sock, data):
"""
Explicitly defined Read Event Handler
This evens is triggered by the underlying TCPServer Component when
a connected client has some data ready to be processed.
Here we simply fire a cooresponding write event to the cooresponding
matching client which we lookup using the socket object as the key
to determinte the unique id.
"""
client = self._clients[sock]
self.fire(write(data), client.channel)
def sanitize(s):
if ':' in s:
address, port = s.split(':')
port = int(port)
return address, port
return s
def main():
opts, args = parse_options()
source = sanitize(args[0])
target = sanitize(args[1])
if type(source) is not tuple:
print('ERROR: source address must specify port (address:port)')
raise SystemExit(-1)
if type(target) is not tuple:
print('ERROR: target address must specify port (address:port)')
raise SystemExit(-1)
system = PortForwarder(source, target)
if opts.daemon:
Daemon('portforward.pid').register(system)
if opts.debug:
Debugger().register(system)
system.run()
if __name__ == '__main__':
main()
|