[tproxy] TProxy version 4.0.0 released

Jan Engelhardt jengelh at computergmbh.de
Fri Aug 3 00:39:18 CEST 2007

On Aug 2 2007 15:45, Cameron Schaus wrote:
>Jan Engelhardt wrote:
>>> How can I make sure packets get routed instead of bridged?  Does this involve
>>> using the brouting feature of ebtables?
>> Yes.
>> In some network layouts, you can use a half-bridge (which is a cool 
>> thing but probably requires the same number of steps) to reduce the 
>> number of needed ebt rules.
>Thanks, using ebtables brouting does appear to work.  However, it may
>be cumbersome for my application to use ebtables rules to keep certain
>traffic off the bridge while allowing unproxied traffic across the
>I have a proxy application running on the bridge IP address, and
>iptables rules currently direct traffic of interest to the proxy.  I
>want to use the tproxy code to perform a foreign connect using the
>client's IP address.  So the client's and server's addresses are more
>or less arbitrary.  This makes generating ebtables brouting rules that
>preserve the bridge behavior for non-proxied traffic difficult.

I'll just give an example case:

eth0 -- ISP-side -- my address
        Objects: Exactly one ISP router at

eth1 -- LAN -- my address
        Objects: Any number of clients in

And we'd like to filter some URLs with a squid running on .34.2.

Step 1: Interfaces (of course you do this with your distro-specific
config files), but the outline is:

	ip a a dev eth0
	ip a a dev eth1

Yes, we have got overlapping networks, but that does not hurt, as the one with
the tighter prefix length (32 wins over 24) has higher precedence. As
I said, this cannot be used for all setups (especially where both
segments contain changing hosts).
So everything works as usual. On the clients, you may need an extra route:

	ip r a via

but only if they should send packets there.
[Default gateway for clients is of course .34.2.]

Step 2: Configure eth0 to do ARP reply

	# Our so-called "half bridge"
	brctl addbr br0
	brctl addif br0 eth0

	# ARP requests need to be handled by ebtables - hence they
	# _do_ need to be bridged (ACCEPT).
	ebtables -t broute -P BROUTING DROP;
	ebtables -t broute -A BROUTING -p arp \
	--opcode request -j ACCEPT;

	ebtables -t nat -A PREROUTING -p arp --opcode request \
	-j arpreply --arpreply-mac `cat /sys/class/net/br0/address` \
	--arpreply-target DROP;

Note that you can also bridge all ARP traffic, i.e. let the clients
answer ARP. I do not consider that necessary.

That's it already. On the .34.2 server, squid is run with
server-side-transparency ("tproxy") and, optionally
client-side-transparency if wanted.

The benefit of this is that no packet can ever be accidentally
bridged ("slip through"), because the bridge consists of only one
port. The other benefit (of using DROP in broute) is that packets
come through regular interfaces instead of br0, making accounting
more precise, and you do not have to use -m physdev in iptables.

>What is currently stopping the packets from being diverted locally
>once they enter the bridge?  As I understand it now, the packets
>destined for the foreign IP address should enter the bridge, and since
>they are destined for the bridge MAC address

Generally, people set it up differently, so that br0 encompasses both
eth0 and eth1. It works too, but needs a bit more thought:

Your bridge sends a packet with a foreign address. So the
ISP router will ask "arp who-has .34.99", and a client responds with
".34.99 at MAC macof3499". Then the router will send whatever IPv4
packet it wanted to send -- to macof3499, NOT to macofbridge.

Hence, the packet gets bridged through the blue level (see
http://www.imagestream.com/~josh/PacketFlow-new.png ). But for
tproxying to be effective, the packet needs to hit the "routing
decision (PRDB)" circle.[1]
There are ways to achieve that:

 - DROP non ARP-packets in the broute table
   (= inject them into the route stack - and hence tproxy)
   path: bridging process, brouting, routing process, Green Level.

 - ebt_dnat packets in the nat table (= change macof3499 to
   path: bridging process, brouting, blue prerouting, bridging
   decision, *then* moves up to the Green Level

Hope this explains things a bit :-)

>they should enter the
>correct protocol handler.  At some point the frames should enter IP
>tables PREROUTING where the tproxy code is invoked.  However,
>something isn't right.  Perhaps it's because the packet device is
>replaced with the bridge device and this doesn't match the socket
>information?  I'd like to understand what isn't working in this case.
>One way around this is to add a check in br_handle_frame to get the
>socket and check if inet->freebind is set, similar to the tproxy
>prerouting code.  One drawback of this is that fragmented IP packets
>cannot be reassembled to obtain the IP addresses and ports, and would
>end up lost in the stack.  An ebtables module could likely be written
>to avoid modifying the bridge code.
>Are there better ways of getting these foreign packets into the
>network stack when they are destined for a local bridge interface?

[ And if you are concerned about xt_socket from Krisztian's tproxy, well,
that's related to the routing process, where we also have to either
send the packet upwards (into INPUT - yes we want this) - since if we
did not, it would be forwarded to the right to the real client. ]


More information about the tproxy mailing list