After reading a bit about TPROXY (e.g at https://www.kernel.org/doc/html/latest/networking/tproxy.html ) I now have more questions then answers. I actually don't even know what TPROXY should do...

Some assumptions about what I should do and what happens inside.
Can you correct the following assumptions ?

From what i understand these are the commands that you should run (although i have no idea why):

  • iptables -t mangle -N DIVERT :
    • A chain named DIVERT is created.
    • You can choose the name. (As long as it's the same in all commands).
    • It has to be part of mangle because you will being doing things that are less trivial than redirecting, blocking and NAT.
  • iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT :
    • The PREROUTING chain makes sure that once a TCP packet is passed from a networkdevice to the kernel, the very first thing that will happen is that it is being sent to the DIVERT chain.
    • -p tcp makes sure that this it is not the case for non-TCP traffic .
    • -m socket makes sure that this it is not the case for packets that create and close the connection (e.g. SYN/ACK)
    • By removing -p tcp -m socket TPROXY will affect all IP(v4) packets. It will be a different, but working, setup.
  • iptables -t mangle -A DIVERT -j MARK --set-mark 1 :
    • The kernel will mark those packets with the number 1. You can choose another number.
    • It's also possible to add multiple marks to a packet. For example: By adding the command iptables -t mangle -A DIVERT -i eth0 -j MARK --set-mark 2 you would make sure that all TCP-packages get the mark 1 and all TCP-packages that arrive from eth0 get both the mark 1 and 2.
    • "Marking with number X" just means "categorizing as member of category X without actually changing anything in the packet".
    • Both the kernel and programs in userspace can read the mark(s) of packets
    • Only the kernel can mark packets
  • iptables -t mangle -A DIVERT -j ACCEPT : By default the kernel discards the packets so you are now making sure it doesn't.
  • ip rule add fwmark 1 lookup 100 :
    • Instead of using the default routingtable, all packets with mark 1 now use a table named 100.
    • You can use choose another number, as long as you make sure that you use the same number everywhere else
  • ip route add local dev lo table 100 :
    • Creates table 100 if it didn't exist already
    • Adds a routing roule that makes sure that all packages that originate from our system (local) stay local by sending them back to lo
    • That this is the case for packages with any destination (each ipv4 adddress is a member of this subnet)
    • But that it's not the case for packages that are not marked 1 (otherwise they wouldn't end up in 100)
  • iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 50080:
    • All packets sent to tcp/80 receive the mark 1 and end up at tcp/50080
    • For some, to me, unknown reason, they are marked. (It looks to me that they pass by DIVERT anyway where they are marked again)
    • For some, to me, unknown reason 0x1 is written twice

My assumption about what the purpose of TPROXY is: Re-routing packets without altering them

  • -t mangle ... --tproxy-mark 0x1/0x1 --on-port xxxx: you modify the packet setting the mark, this is before routing -> ip rule add fwmark 1 lookup 100: the rule catch the packets marked and looks up on the 100 routing table -> ip route add local dev lo table 100: everything by default ( will go to dev lo (localhost). So, the marked packets will go to localhost on port xxxx.
    – Ictus
    Commented Jun 13, 2022 at 5:02

2 Answers 2


"Re-routing without altering" is basically technically correct, but to understand what it's for it's better to think "intercepting" - you're usually only "re-routing" to a program you wrote, running on the same machine (which ought to be the client's wifi access point, or something similarly positioned between them and the rest of the world). It's a way to get, within your C/C++/whatever code, what looks like a normal TCP socket you can send() and recv() on, but is actually letting you impersonate their intended destination.

A use would be transparently proxying traffic through some setup so exotic that not even e.g. a carefully configured Wireguard can handle it, and instead you need to write your own actual program to make it work.

Take a look at this: https://github.com/FarFetchd/simple_tproxy_example

It's a minimal working example of the simplest interesting thing you can do with this, which might give you a better intuition of the "why".

As for the ip rule fwmark stuff, I advise you to find an example that works for you and just treat it as a black magic incantation, unless you are trying to get capable of doing serious dev work on the Linux networking stack itself. I mean I consider myself basically competent with iptables, and have done some serious useful work with TPROXY, and I still find the ip rule fwmark stuff totally mysterious, haha.


For your first "unknown reason", packets matched by DIVERT are accepted, which means they do not go through remaining rules, and do not go to the second mark place.

For you second "unknown reason", the two 0x1 are value and mask.

You may find man page of iptables and iptables-extensions helpful.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .