On Wed, 2008-11-12 at 11:40 +0000, Andrey Luzgin wrote:
Hello,
While I can see example of using udp on tproxy2 onto the redirect-udp-recv.c file, I can't find equivalent on tproxy4.
For getting the original destination IP, I just use setsockopt IP_PKTINFO: setsockopt(sd, SOL_IP, IP_PKTINFO , &flags, sizeof(flags));
But I don't know how to get the original destination port:
a) I manually defined IP_RECVORIGADDRS to be 11273 as I find on tproxy2: setsockopt(sd, SOL_IP, IP_RECVORIGADDRS , &flags, sizeof(flags)); but the setsockopt failed.
b) the getsockname give me the server listening port.
Here are my iptables\ip route redirection lines: ${iptables} -t mangle -N DIVERT ${iptables} -t mangle -A PREROUTING -p udp -m socket -j DIVERT ${iptables} -t mangle -A DIVERT -j MARK --set-mark 1 ${iptables} -t mangle -A DIVERT -j ACCEPT ${iptables} -t mangle -A PREROUTING -p udp --dport 1500 -j TPROXY --tproxy-mark 1 --on-port 3127
ip rule add fwmark 1 lookup 100 ip route add local 0.0.0.0/0 dev lo table 100
Well, for supporting UDP with tproxy4 we use a different approach: udp_accept(), you can find it in the BalaBit kernel patch tree at http://www.balabit.com/downloads/files/kernel-patches/ The way udp_accept() works is as follows: * the userspace proxy opens a "listening" udp socket, binds it to the listening address, performs no connect() calls * tproxy redirects packets to this socket just like in the case for TCP * whenever the socket becomes readable from the userspace proxy, accept() is invoked on the UDP socket, this accept() is implemented by the patch mentioned above * in kernel space: the first packet is consulted from the socket buffer of the listening socket * the kernel opens a new UDP socket, just like the accept() call for TCP does * this new UDP socket is bound this way: * local address is the same as the destination address of the incoming packet * destination address is the same as the source address of the incoming packet * the socket buffer of the listening socket is traversed, and each packet having the same IP addresses as the first packet is moved to the newly opened socket; this traversal is happening in an atomic context, thus no new packets can arrive * a reference to the newly opened socket is returned to userspace * when a new packet comes in, the socket lookup will prefer the completely bound socket over the listening socket Since at the end of the accept() call you get a completely bound socket, you can simply call getsockname() to query the target address, just like with TCP. Hope this helps. PS: I was talking to Patrick McHardy whether to send the udp_accept() patch for kernel inclusion, he said it might be worth trying, however he was not completely sure it'd be integrated. So I didn't push it so far. -- Bazsi