A Simple UDP Forwarder in Twisted
I recently found myself in need of a quick-and-dirty way to forward UDP packets from one machine to another. SSH port forwarding was out, unfortunately, as the source host was Windows machine and I wasn’t about to install Cygwin or MSYS, etc. After a brief and unsuccessful search for simple tools to accomplish this, I decided to whip something up myself. The project I was working on was already using python with the Twisted networking library, so that’s what I used. I tried to make it as flexible as possible, allowing forwarding to multiple hosts and name resolution, while keeping it as simple as I could. Here’s the result:
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
# edit this to map local port numbers to a list of host:port destinations
= {
forwardMap 5500 : [ "192.168.110.32:5500", "10.0.1.1:5500" ],
5499 : [ "192.168.110.32:5499" ],
15501 : [ "localhost:5501" ]
}
class Forward(DatagramProtocol):
def __init__(self, targetTuples):
self._targetTuples = targetTuples
def datagramReceived(self, data, (host, port)):
for targetHost, targetPort in self._targetTuples:
self.transport.write(data, (targetHost, targetPort))
def bindListeners(resolvedMap):
for port, targetPairs in resolvedMap.items():
reactor.listenUDP(port, Forward(targetPairs))
def resolved(ip, lport, host, dport, rmap={}):
rmap.setdefault(lport, []).append((ip, dport))= lambda a, b: a + b
cons if (len(reduce(cons, forwardMap.values())) == len(reduce(cons, rmap.values()))):
bindListeners(rmap)
for port, destinations in forwardMap.items():
= [d.split(':') for d in destinations]
strPairs map(lambda (host, dport): (reactor.resolve(host).addCallback(resolved, port, host, int(dport))), strPairs)
reactor.run()
The most current code can always be found in this gist.