^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) .. SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) =========================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) Transparent proxy support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) =========================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) This feature adds Linux 2.2-like transparent proxy support to current kernels.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) To use it, enable the socket match and the TPROXY target in your kernel config.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) You will need policy routing too, so be sure to enable that as well.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) From Linux 4.18 transparent proxy support is also available in nf_tables.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) 1. Making non-local sockets work
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) ================================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) The idea is that you identify packets with destination address matching a local
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) socket on your box, set the packet mark to a certain value::
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) # iptables -t mangle -N DIVERT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) # iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) # iptables -t mangle -A DIVERT -j MARK --set-mark 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) # iptables -t mangle -A DIVERT -j ACCEPT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) Alternatively you can do this in nft with the following commands::
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) # nft add table filter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) # nft add chain filter divert "{ type filter hook prerouting priority -150; }"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) # nft add rule filter divert meta l4proto tcp socket transparent 1 meta mark set 1 accept
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) And then match on that value using policy routing to have those packets
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) delivered locally::
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) # ip rule add fwmark 1 lookup 100
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) # ip route add local 0.0.0.0/0 dev lo table 100
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) Because of certain restrictions in the IPv4 routing output code you'll have to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) modify your application to allow it to send datagrams _from_ non-local IP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) addresses. All you have to do is enable the (SOL_IP, IP_TRANSPARENT) socket
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) option before calling bind::
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) fd = socket(AF_INET, SOCK_STREAM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) /* - 8< -*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) int value = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) setsockopt(fd, SOL_IP, IP_TRANSPARENT, &value, sizeof(value));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /* - 8< -*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) name.sin_family = AF_INET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) name.sin_port = htons(0xCAFE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) name.sin_addr.s_addr = htonl(0xDEADBEEF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) bind(fd, &name, sizeof(name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) A trivial patch for netcat is available here:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) http://people.netfilter.org/hidden/tproxy/netcat-ip_transparent-support.patch
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) 2. Redirecting traffic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) ======================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) Transparent proxying often involves "intercepting" traffic on a router. This is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) usually done with the iptables REDIRECT target; however, there are serious
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) limitations of that method. One of the major issues is that it actually
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) modifies the packets to change the destination address -- which might not be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) acceptable in certain situations. (Think of proxying UDP for example: you won't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) be able to find out the original destination address. Even in case of TCP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) getting the original destination address is racy.)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) The 'TPROXY' target provides similar functionality without relying on NAT. Simply
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) add rules like this to the iptables ruleset above::
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) # iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) --tproxy-mark 0x1/0x1 --on-port 50080
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) Or the following rule to nft:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) # nft add rule filter divert tcp dport 80 tproxy to :50080 meta mark set 1 accept
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) Note that for this to work you'll have to modify the proxy to enable (SOL_IP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) IP_TRANSPARENT) for the listening socket.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) As an example implementation, tcprdr is available here:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) https://git.breakpoint.cc/cgit/fw/tcprdr.git/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) This tool is written by Florian Westphal and it was used for testing during the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) nf_tables implementation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) 3. Iptables and nf_tables extensions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) ====================================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) To use tproxy you'll need to have the following modules compiled for iptables:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) - NETFILTER_XT_MATCH_SOCKET
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) - NETFILTER_XT_TARGET_TPROXY
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) Or the floowing modules for nf_tables:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) - NFT_SOCKET
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) - NFT_TPROXY
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) 4. Application support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) ======================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 4.1. Squid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) ----------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) Squid 3.HEAD has support built-in. To use it, pass
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) '--enable-linux-netfilter' to configure and set the 'tproxy' option on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) the HTTP listener you redirect traffic to with the TPROXY iptables
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) target.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) For more information please consult the following page on the Squid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) wiki: http://wiki.squid-cache.org/Features/Tproxy4