Transport layer transparent intercepting proxy.
Project description
transmitm
transmitm
is a Twisted-based Python module that provides transparent intercepting proxying at transport level.
Transports supported as of the latest version:
- TCP
- UDP
Install
transmitm
requires a 3.5
minimum version of Python
pip install transmitm
Operation
Transparent proxying requires traffic redirection to the app using a third party utility such as iptables
or nftables
.
iptables
example to redirect TCP traffic targeting server port 80 to proxy port 8080
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
transmitm
uses the concept of taps. Tap
is 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 to Proxy
objects (TCPProxy
, UDPProxy
) that handle packets on two arms - both from the client and the server.
Dispatcher
class holds a list of proxy instances; it cannot be instantiated.
+---------------------------------------------+
| proxy |
| +--------+ +--------+ +-------+ |
| | | | | | | |
SDU | | | | | | |
client ------>-----+ tap 1 +---> tap 2 |...| tap n +---------> server
| | | | | | | |
| | | | | | | |
| +--------+ +--------+ +-------+ |
+---------------------------------------------+
gateway
Usage / API
The following script illustrate the module's API
#!/usr/bin/env python3
from transmitm import Tap, 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 chain
class PktLogger(Tap):
"""Prints packet size to stdout
"""
def handle(self, data, ip_tuple):
"""Not altering data parameter causes returning
the same object reference"""
peer, proxy = ip_tuple
print(f"Got {len(data)} bytes from {peer} on {proxy}")
return data
class Mangler(Tap):
"""Do a search and replace in packet bytes
"""
def __init__(self, search, replace):
self.search = search
self.replace = replace
def handle(self, data, ip_tuple):
return data.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:8080
tcp_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 localhost
udp_proxy_53 = UDPProxy("1.1.1.1", 53, bind_port=53)
# The proxy can be used as a connector between IPv4 and IPv6 endpoints
udp_proxy_rnd = UDPProxy("1.1.1.1", 53, interface='::0')
# Create tap instances that will process packets
logger = 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 chaining
tcp_proxy_8080.add_tap(path_mangler)
tcp_proxy_8080.add_tap(logger)
# Just logging for DNS packets
udp_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 ones
Dispatcher.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 Dispatcher
print("Registered proxies:")
for proxy in Dispatcher.proxies:
print(
proxy.__class__.__name__,
proxy.interface,
proxy.bind_port,
'->',
proxy.server_ip,
proxy.server_port
)
# Blocking method, should be called last
Dispatcher.run()
TODO
- Add UNIX Domain sockets support
- Add packet routing capabilities
Bug reporting
- Open a new issue
- Explain expected vs actual behavior
- Add code snippet that reproduces the issue
Contributing
This project uses poetry for package management during development. Development dependencies require a >=3.7
version of Python. To get a working environment use the following commands
# Install poetry
pip install poetry
# or...
# curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
# Install module's development dependencies
poetry install --no-root
# Check the setup by running the test
pytest
- Fork the repo
- Check out a feature or bug branch
- Add your changes
- Add test cases
- Update README when needed
- Ensure tests are passing
- Submit a pull request to upstream repo
- Add description of your changes
- Ensure branch is mergeable
MIT License, 2020 @tim17d
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
File details
Details for the file transmitm-0.1.0-py3-none-any.whl
.
File metadata
- Download URL: transmitm-0.1.0-py3-none-any.whl
- Upload date:
- Size: 23.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/39.0.1 requests-toolbelt/0.9.1 tqdm/4.48.0 CPython/3.7.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 00e4ab7d5aff40169128a22b77d7c469c659de74fef539d350f4b3112a6bcbbd |
|
MD5 | 94cf164c4b6757ffa97e5932ba45235c |
|
BLAKE2b-256 | 0c45f47a12537f92f5e45435b787ef7f7ce23f1d895273d581fb38c433299047 |