[tproxy] udp + tproxy

Balazs Scheidler bazsi at balabit.hu
Wed Nov 12 20:19:15 CET 2008

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
> 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 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

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
  * 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.


More information about the tproxy mailing list