Prerequisites

TCP connections originated by root to 1024 port moved to a separate routing domain:

$ iptables -t mangle -S OUTPUT # output simplified
-A OUTPUT -p tcp -m owner --uid-owner root -m tcp --dport 1024 -m state --state NEW,RELATED -j CONNMARK --set-xmark 0x10/0x10
-A OUTPUT -p tcp -m owner --uid-owner root -m tcp --dport 1024 -j CONNMARK --restore-mark
$ ip route add default dev lo scope link table 0x10
$ ip rule add fwmark 0x10/0x10 lookup 0x10

Results

Testing this bit from documentation:

int value = 1;
setsockopt(fd, SOL_IP, IP_TRANSPARENT, &value, sizeof(value));

When listener is running from non-root or without IP_TRANSPARENT option, it cannot receive connections. Series of SYN attempts can be observed on the interface when trying to initiate TCP session. Probably it makes sense to test UDP as well.

Connection can be established when listener is running with root UID and IP_TRANSPARENT option is set. Of course, client should run with root UID too.

After a successful connection route recorded in cache, it is possible to run listener with any UID and not setting IP_TRANSPARENT option. Client (with root UID) will successfully establish connections anyway. Until «ip route flush cached».

Analysis

Listener socket should be in the same routing domain with client socket. Though this statement should be tested: «Enabling this socket option requires superuser privileges (the CAP_NET_ADMIN capability)».

Server applications should enable IP_TRANSPARENT option.

Once loaded, module nf_tproxy_core cannot be removed back.