Package: transmitm
transmitmtransmitmis a Twisted-based Python module that provides transparent intercepting proxying at transport level.Transports supported as of the latest version:TCPUDPInstalltransmitmrequires a3.5minimum version of Pythonpip install transmitmOperationTransparent proxying requires traffic redirection to the app using a third party utility such asiptablesornftables.iptablesexample to redirect TCP traffic targeting server port 80 to proxy port 8080iptables-tnat-APREROUTING-ieth0-ptcp--dport80-jREDIRECT--to-port8080transmitmuses the concept of taps.Tapis a class whose instances receive transport SDUs (Service Data Units) from transitioning packets and perform some sort of operation on them; multiple taps are chained.Taps get attached toProxyobjects (TCPProxy,UDPProxy) that handle packets on two arms - both from the client and the server.Dispatcherclass holds a list of proxy instances; it cannot be instantiated.+---------------------------------------------+
             |                    proxy                    |
             |     +--------+   +--------+   +-------+     |
             |     |        |   |        |   |       |     |
            SDU    |        |   |        |   |       |     |
client ------>-----+  tap 1 +---> tap 2  |...| tap n +---------> server
             |     |        |   |        |   |       |     |
             |     |        |   |        |   |       |     |
             |     +--------+   +--------+   +-------+     |
             +---------------------------------------------+
                                 gatewayUsage / APIThe following script illustrate the module's API#!/usr/bin/env python3fromtransmitmimportTap,Dispatcher,TCPProxy,UDPProxy# Define Tap classes that handle data (SDUs)# At minimum, they must implement the 'handle' method# The returned value gets passed to the next tap in chainclassPktLogger(Tap):"""Prints packet size to stdout"""defhandle(self,data,ip_tuple):"""Not altering data parameter causes returningthe same object reference"""peer,proxy=ip_tupleprint(f"Got{len(data)}bytes from{peer}on{proxy}")returndataclassMangler(Tap):"""Do a search and replace in packet bytes"""def__init__(self,search,replace):self.search=searchself.replace=replacedefhandle(self,data,ip_tuple):returndata.replace(self.search,self.replace)# Create proxy instances# A Proxy object requires at least a destination server's IP and port number# Listen on TCP 8081 and forward to 127.0.0.1:8080tcp_proxy_8080=TCPProxy("127.0.0.1",8080,bind_port=8081)# Bind port may be omitted for getting a random one# You can also specify a bind interface; by default all proxies are bind to localhostudp_proxy_53=UDPProxy("1.1.1.1",53,bind_port=53)# The proxy can be used as a connector between IPv4 and IPv6 endpointsudp_proxy_rnd=UDPProxy("1.1.1.1",53,interface='::0')# Create tap instances that will process packetslogger=PktLogger()path_mangler=Mangler(search=b'/api',replace=b'/forbidden')# Attach taps instances to the proxies# The order in which the taps are added defines the tap chainingtcp_proxy_8080.add_tap(path_mangler)tcp_proxy_8080.add_tap(logger)# Just logging for DNS packetsudp_proxy_53.add_tap(logger)# When registering multiple proxies make sure you add those with a specified# bind_port first, to avoid collision with randomly assigned onesDispatcher.add_proxies([tcp_proxy_8080,udp_proxy_53,udp_proxy_rnd])# If not provided, bind port is randomly assigned and can be retrieved# after adding the proxy to the Dispatcherprint("Registered proxies:")forproxyinDispatcher.proxies:print(proxy.__class__.__name__,proxy.interface,proxy.bind_port,'->',proxy.server_ip,proxy.server_port)# Blocking method, should be called lastDispatcher.run()TODOAdd UNIX Domain sockets supportAdd packet routing capabilitiesBug reportingOpen a new issueExplain expected vs actual behaviorAdd code snippet that reproduces the issueContributingThis project usespoetryfor package management during development. Development dependencies require a>=3.7version of Python. To get a working environment use the following commands# Install poetrypipinstallpoetry# or...# curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python# Install module's development dependenciespoetryinstall--no-root# Check the setup by running the testpytestFork the repoCheck out a feature or bug branchAdd your changesAdd test casesUpdate README when neededEnsure tests are passingSubmit a pull request to upstream repoAdd description of your changesEnsure branch is mergeableMIT License, 2020@tim17d