[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
> 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
More information about the tproxy
mailing list