I am trying to write an iptables rule that will redirect all outgoing UDP packets to a local socket, but I also need the destination information. I started out with
sudo iptables -t nat -A sshuttle-12300 -j RETURN --dest 127.0.0.0/8 -p udp
sudo iptables -t nat -A sshuttle-12300 -j REDIRECT --dest 0.0.0.0/0 -p udp --to-ports 15000
And that's great, now I can get all outgoing UDP packets by using a socket on port 15000.
Now, I need the destination information (target host and port number) so a simple UDP socket isn't enough; need a raw socket so that it gets the full IP header.
However, as it turns out, the packets received seem to be addressed for localhost:15000. This makes sense because that's where the socket is, but that's not what I want; I want the host/port before the packet was redirected by iptables.
Googling led to this question, with the answer suggesting two approaches: TPROXY and SO_ORIGINAL_DST, recommending the former, so that's what I tried to go with.
Added the iptables rule for TPROXY:
sudo iptables -t mangle -A PREROUTING -j TPROXY --dest 0.0.0.0/0 -p udp --on-port 15000
Reading from tproxy.txt, we need to create a listening socket with the IP_TRANSPARENT option (this is done as root):
from socket import *
s = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)
# The IP_TRANSPARENT option isn't defined in the socket module.
# Took the value (19) from the patch in http://bugs.python.org/issue12809
s.setsockopt(SOL_IP, 19, 1)
s.bind(('0.0.0.0', 15000))
s.recv(4096) # Will hang until it receives a packet
Alright, now let's write another script to generate a test packet to see if anything happens:
from socket import *
s = socket(AF_INET, SOCK_DGRAM)
s.connect(('192.168.1.1', 9001))
s.send('hello')
But then nothing happens on the receiving side. The recv call seems to hang, not receiving any data.
So, the overall question is either:
- Is there something wrong in the code to receive the data from the
TPROXYrule?
or
- Is there another way to achieve this (redirect all outgoing UDP packets to a local socket with a way to get the destination information)?
Edit: I should insist that I'd like to redirect (therefore intercept) the packets, not just inspect them as they go through.
TPROXYrule? It is bound on0.0.0.0to bind on all interfaces, but perhaps127.0.0.1would be sufficient to bind on the local interface. I didn't really understand the second part of your comment... you mean if I remove theiptablesrules defined at the top? Then UDP packets would be allowed out, and I don't want that. TheTPROXYpart of the question is separate (I didn't have thoseiptablesrules set when doing theTPROXYthings). - Etienne Perotiptablesentries when doing theTPROXYpart, so the source/destination addresses shouldn't be lost (and I need them, so it is not acceptable to lose them) - Etienne Perot