I have a self-written interface tun0 (TUN/TAP based) that outputs what it receives.
I need all traffic of the system to flow through this interface.
The role of the interface is:
- To figure out packets likely to be censored and tunnel them.
- Pass all other traffic untouched.
As you guess I am trying to build an anticensorship tool.
Decision about tunneling must be taken inside tun0 process
because only there we may use trusted DNS.
I need your help to show me how to make all traffic flow through a self-written interface tun0. If tun0 needs changes I ask you to provide such changes.
Below is how I tried to make all traffic go through tun0 and failed (pings fail).
Compiling
gcc tun0.c
sudo ./a.out
Configuring
sudo ip addr add 10.0.0.1/24 dev tun0
-
create table John
$ cat /etc/iproute2/rt_tables # # reserved values # 255 local 254 main 253 default 0 unspec # # local # #1 inr.ruhep 200 John
Order is important:
sudo ip rule add from all lookup John
sudo ip route add default dev tun0 table John
-
sudo ip rule add iif tun0 lookup main priority 500
$ ip rule 0: from all lookup local 500: from all iif tun0 lookup main 32765: from all lookup John 32766: from all lookup main 35000: from all lookup default
Troubleshooting
-
sudo tcpdump -i wlp2s0 -qtln icmp
and thenping -I tun0 8.8.8.8
shows no packets captured, it means no packets are transmitted from tun0 to wlp2s0 viaiif tun0 lookup main
rule. -
When I replaced
tun0
withlo
everywhere then it worked for me.
Also Tried
- Turning off reverse path filtering,
rp_filter=0
in/etc/sysctl.conf
Answer Troubleshooting
iptables -I FORWARD -j LOG --log-prefix "filter/FORWARD "
iptables -t nat -I OUTPUT -j LOG --log-prefix "nat/OUTPUT "
iptables -t nat -I PREROUTING -j LOG --log-prefix "nat/PREROUTING "
iptables -t nat -I POSTROUTING -j LOG --log-prefix "nat/POSTROUTNG "
tail -f /var/log/syslog
Modified sources from answer are also here.
Best Answer
So in your configuration, all the packets you try to send to the network initially originating from
10.0.0.1
(because they are going throughtun0
interface and its local address is10.0.0.1
). You capture the packets, everything is fine so far.Now,
tun0
sends the packets further. Source address is10.0.0.1
and you want the packets to leave through a different interface (wlp2s0
in your case). That's routing so let's enable routing first:After that, if you'll look at
tcpdump
forwlp2s0
you can notice the packets leave with source address10.0.0.1
and not with the source address of the wlan interface (what you would expect I guess). So we need to change the source address and it's called source NAT. In linux it's easy with help of netfilter/iptables:Please also check that your
FORWARD
chain hasACCEPT
policy or you would need to allow forwarding with something like:Everything should work now: linux kernel does the routing, it's moving packets from
tun0
interface towlp2s0
. netfilter should change the source IP10.0.0.1
to yourwlp2s0
interface assigned address for output packets. It memorizes all the connections and when the reply packets go back (if they) it changes the destination address of thewlp2s0
interface assigned address to10.0.0.1
(the "conntrack" feature).Well, it should but it doesn't. It seems, netfilter gets confused with this complicated routing configuration and the fact that the same packet first goes through the
OUTPUT
chain and then being routed and comes toPREROUTING
chain. At least on by Debian 8 box it doesn't work.The best way to troubleshoot netfilter is the
TRACE
feature:I only enable tracing for ICMP packets, you may use other filter to debug.
It will show what tables and chains the packet goes through. And I can see that the packet goes no further the
FORWARD
chain (and it's not being caught by thenat/POSTROUTING
chain that actually doesSNAT
).Below are several approaches to make this work.
APPROACH #1
The best way to un-confuse netfilter is to change the source IP address of packets in
tun0.c
application. It's also the most natural way. We need to change 10.0.0.1 to 10.0.0.2 on the way outwards and 10.0.0.2 to 10.0.0.1 on the way back.I've modified
tun0.c
with source address change code. Here is the new file and here is patchfile for yourtun0.c
. Changes to IP header also involve checksum correction, so I took some code from OpenVPN project. Here is the full list of commands I execute after a clean reboot andtun0_changeip.c
launch:Please note that you don't need to turn off the reverse path filtering in that case, because everything is legal -
tun0
only receives and sends packets that belong to its subnet. Also you can do a source-based routing instead of interface-based.APPROACH #2
It's possible to do
SNAT
before the packet reachtun0
interface. It's not very correct though. You will definitely need to turn off the reverse path filtering in this case:Now, do
SNAT
: iptables -t nat -A POSTROUTING -o tun0 -s 10.0.0.1 -j SNAT --to-source ip.address.of.your.wlan.interfaceHere we change the source address just before the packets reach the
tun0
device.tun0.c
code resend these packets "as is" (with changed source address) and they are successfully routed through wlan interface. But you might have a dynamic IP on wlan interface and want to useMASQUERADE
(in order to not specify the interface address explicitly). Here is how you can make use ofMASQUERADE
:Please note the "
10.0.55.1
" IP address - it's different. You can use any IP here, it doesn't matter. The packets reachnat/POSTROUTING
chain onwlp2s0
interface if we change the source IP before. And now it's not dependent on a static IP for wlan interface.APPROACH #3
You can also use
fwmark
. That way you don't needSNAT
but you'll capture only outgoing packets:First we need to disable reverse path filtering for
tun0
because it will forward packets that belong to another network:That's another "hack" for routing and netfilter that works on my Debian 8 box, but still I recommend to take the first approach as it's more natural and doesn't use any hacks.
You may also consider to build your application as a transparent proxy. I think it would be much easier instead of analyzing packets from tun device.