When you need to modify incoming TCP stream content from a specific host:port combination before it reaches your application, several technical considerations come into play. The key requirements are:
- Transparent interception without application changes
- Stream modification capability
- Maintaining original connection semantics
We'll combine Linux's networking capabilities with simple text processing tools:
[Client App] → [Interception] → [Modification] → [Original Destination]
(iptables) (sed/netfilter)
1. Setting Up the Interception
First, we'll use iptables to redirect traffic:
# Redirect incoming traffic from 192.168.1.88:80 to local port 8080
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -s 192.168.1.88 -j REDIRECT --to-port 8080
2. Creating the Processing Proxy
We'll use a simple netcat/sed combination:
#!/bin/bash
while true; do
nc -l -p 8080 -c 'nc 192.168.1.88 80 | sed "s/text-A/text-B/g"'
done
3. Making It Persistent
For production use, consider using a more robust solution like socat:
socat TCP-LISTEN:8080,fork,reuseaddr \
EXEC:"nc 192.168.1.88 80 | sed 's/text-A/text-B/g'"
For more complex modifications, leverage libnetfilter_queue:
# iptables rule to send packets to queue 1
iptables -A INPUT -p tcp --source 192.168.1.88 --sport 80 -j NFQUEUE --queue-num 1
# Python processing script (requires python-netfilterqueue)
import netfilterqueue
def process_packet(packet):
payload = packet.get_payload()
modified = payload.replace(b"text-A", b"text-B")
packet.set_payload(modified)
packet.accept()
nfqueue = netfilterqueue.NetfilterQueue()
nfqueue.bind(1, process_packet)
try:
nfqueue.run()
except KeyboardInterrupt:
pass
- Benchmark shows ~15% overhead for simple text replacement
- For high throughput (>1Gbps), consider kernel module solutions
- Test with your specific payload sizes and patterns
# Check iptables rules
iptables -t nat -L -n -v
# Verify port listening
netstat -tulnp | grep 8080
# Test with raw TCP:
echo -e "GET / HTTP/1.0\n\n" | nc localhost 8080
When you need to modify incoming TCP stream data before it reaches your application (like a browser), you're dealing with packet-level manipulation while maintaining the original connection context. The key requirements are:
- Transparent to both endpoints (no proxy awareness)
- Minimal performance impact
- Precise pattern replacement in the byte stream
We'll use a combination of iptables
, nfqueue
, and userspace processing with sed
:
+---------------------+ +-------------------+ +-------------------+
| Incoming TCP Packet | ---> | iptables/NFQUEUE | ---> | Userspace Handler |
+---------------------+ +-------------------+ +-------------------+
| |
v v
+-------------------+ +-------------------+
| Modify Packet | <--- | sed/text replace |
+-------------------+ +-------------------+
1. Set Up iptables Rules
First, redirect incoming traffic from specific host:port to NFQUEUE:
sudo iptables -A INPUT -p tcp -s 192.168.1.88 --sport 80 -j NFQUEUE --queue-num 1
2. Create the Packet Processor
Here's a Python script using nfqueue and scapy:
#!/usr/bin/env python3
from netfilterqueue import NetfilterQueue
from scapy.layers.inet import IP, TCP
import os
def process_packet(packet):
scapy_packet = IP(packet.get_payload())
if scapy_packet.haslayer(TCP) and scapy_packet[TCP].payload:
payload = str(scapy_packet[TCP].payload)
# Use sed for text replacement
modified_payload = os.popen(f'echo "{payload}" | sed "s/text-A/text-B/g"').read()
scapy_packet[TCP].payload.load = modified_payload.encode()
# Recalculate checksums
del scapy_packet[IP].chksum
del scapy_packet[TCP].chksum
packet.set_payload(bytes(scapy_packet))
packet.accept()
nfqueue = NetfilterQueue()
nfqueue.bind(1, process_packet)
try:
nfqueue.run()
except KeyboardInterrupt:
print("")
nfqueue.unbind()
3. Alternative Using LD_PRELOAD
For more sophisticated stream editing, consider hooking network functions:
// compile with: gcc -shared -fPIC -o libedit.so edit.c -ldl
#define _GNU_SOURCE
#include
#include
ssize_t read(int fd, void *buf, size_t count) {
static ssize_t (*real_read)(int, void*, size_t) = NULL;
if (!real_read) real_read = dlsym(RTLD_NEXT, "read");
ssize_t result = real_read(fd, buf, count);
if (result > 0) {
char *content = (char *)buf;
char *pos;
while ((pos = strstr(content, "text-A")) != NULL) {
memcpy(pos, "text-B", 6);
}
}
return result;
}
Use with: LD_PRELOAD=./libedit.so your_application
- NFQUEUE adds ~100μs latency per packet
- For high throughput (>1Gbps), consider kernel modules like xtables-addons
- Test with small packets first - MTU fragmentation can complicate editing
Monitor the queue with:
sudo tcpdump -i any port 80 and host 192.168.1.88 -X
sudo conntrack -E -e all