Как заставить весь трафик проходить через один интерфейс в Linux

12

У меня есть самописный интерфейс tun0 (на основе TUN / TAP ), который выводит то, что получает.
Мне нужен весь трафик системы для прохождения через этот интерфейс.
Роль интерфейса:

  1. Выяснить, какие пакеты могут быть подвергнуты цензуре, и туннелировать их.
  2. Пройдите весь остальной транспорт нетронутым.

Как вы догадываетесь, я пытаюсь создать инструмент против цензуры.
Решение о туннелировании должно быть принято внутри процесса tun0,
потому что только там мы можем использовать доверенный DNS.

Мне нужна ваша помощь, чтобы показать мне, как заставить весь трафик проходить через самописный интерфейс tun0. Если tun0 нуждается в изменениях, я прошу вас предоставить такие изменения.

Ниже показано, как я пытался заставить весь трафик проходить через tun0 и потерпел неудачу (сбой проверки связи).

составление

  1. gcc tun0.c
  2. sudo ./a.out

Настройка

  1. sudo ip addr add 10.0.0.1/24 dev tun0
  2. создать таблицу Джон

    $ cat /etc/iproute2/rt_tables 
    #
    # reserved values
    #
    255     local
    254     main
    253     default
    0       unspec
    #
    # local
    #
    #1      inr.ruhep
    
    200 John
    

Заказ важен:

  1. sudo ip rule add from all lookup John
  2. sudo ip route add default dev tun0 table John
  3. 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 
    

Исправление проблем

  1. sudo tcpdump -i wlp2s0 -qtln icmpи затем ping -I tun0 8.8.8.8показывает отсутствие перехваченных пакетов, это означает, что никакие пакеты не передаются от tun0 к wlp2s0 через iif tun0 lookup mainправило.

  2. Когда я заменил tun0с loвсюду , то он работал на меня.

Также попробовал

  1. Отключение фильтрации обратного пути, rp_filter=0в/etc/sysctl.conf

Ответ Устранение неполадок

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

Модифицированные источники из ответа также здесь .

ilyaigpetrov
источник

Ответы:

10

Таким образом, в вашей конфигурации все пакеты, которые вы пытаетесь отправить в сеть, изначально исходят 10.0.0.1(потому что они проходят через tun0интерфейс и его локальный адрес есть 10.0.0.1). Вы захватываете пакеты, пока все в порядке.
Теперь tun0отправляет пакеты дальше. Адрес источника есть, 10.0.0.1и вы хотите, чтобы пакеты выходили через другой интерфейс ( wlp2s0в вашем случае). Это маршрутизация, поэтому давайте сначала включим маршрутизацию:

sysctl -w net.ipv4.ip_forward=1

После этого, если вы будете смотреть на tcpdumpдля wlp2s0вы можете заметить , что пакеты оставить с адресом источника , 10.0.0.1а не с исходным адресом интерфейса беспроводной ЛВС (что можно было бы ожидать , я думаю). Поэтому нам нужно изменить адрес источника, и он называется NAT источника . В Linux это легко с помощью netfilter / iptables :

iptables -t nat -A POSTROUTING -o wlp2s0 -s 10.0.0.1 -j MASQUERADE

Также проверьте, что в вашей FORWARDцепочке есть ACCEPTполитика или вам нужно разрешить пересылку с чем-то вроде:

iptables -A FORWARD -i tun0 -o wlp2s0 -s 10.0.0.1 -j ACCEPT
iptables -A FORWARD -i wlp2s0 -o tun0 -d 10.0.0.1 -j ACCEPT

Теперь все должно работать: ядро Linux выполняет маршрутизацию, оно перемещает пакеты из tun0интерфейса в wlp2s0. netfilter должен изменить IP- адрес источника 10.0.0.1на wlp2s0адрес, назначенный вашему интерфейсу для выходных пакетов. Он запоминает все соединения и, когда ответные пакеты возвращаются (если они есть), меняет адрес назначения назначенного wlp2s0интерфейса интерфейса 10.0.0.1(функция «conntrack»).
Ну, это должно быть, но это не так. Кажется, netfilter путается с этой сложной конфигурацией маршрутизации и тем фактом, что один и тот же пакет сначала проходит через OUTPUTцепочку, а затем маршрутизируется и попадает в PREROUTINGцепочку. По крайней мере, на Debian 8 box это не работает.
Лучший способ устранения неполадок с сетевым фильтром - это TRACEфункция:

modprobe ipt_LOG
iptables -t raw -A OUTPUT -p icmp -j TRACE
iptables -t raw -A PREROUTING -p icmp -j TRACE

Я включаю трассировку только для пакетов ICMP, вы можете использовать другой фильтр для отладки.
Он покажет, через какие таблицы и цепочки проходит пакет. И я вижу , что пакет не идет далее FORWARDцепь (и это не пойманы nat/POSTROUTINGцепи , которая на самом деле делает SNAT).
Ниже приведены несколько подходов, чтобы сделать эту работу.

ПОДХОД № 1

Лучший способ не путать netfilter - это изменить исходный IP-адрес пакетов в tun0.cприложении. Это также самый естественный способ. Нам нужно изменить 10.0.0.1 на 10.0.0.2 на обратном пути и 10.0.0.2 на 10.0.0.1 на обратном пути.
Я изменил tun0.cс кодом изменения исходного адреса. Вот новый файл и вот патч- файл для вашего tun0.c. Изменения в заголовке IP также включают исправление контрольной суммы , поэтому я взял некоторый код из проекта OpenVPN . Вот полный список команд, которые я выполняю после чистой перезагрузки и tun0_changeip.cзапуска:

ifconfig tun0 inet 10.0.0.1/30 up
sysctl -w net.ipv4.ip_forward=1
ip route add default dev tun0 table John
ip rule add from all lookup John
ip rule add from 10.0.0.2 lookup main priority 500
iptables -t nat -A POSTROUTING -o wlp2s0 -s 10.0.0.2 -j MASQUERADE

Обратите внимание, что вам не нужно отключать фильтрацию обратного пути в этом случае, потому что все законно - tun0только получает и отправляет пакеты, которые принадлежат его подсети. Также вы можете сделать маршрутизацию на основе источника вместо интерфейса.

ПОДХОД № 2

Это можно сделать SNATдо того, как пакет достигнет tun0интерфейса. Это не очень правильно, хотя. Вам обязательно нужно отключить фильтрацию обратного пути в этом случае:

sysctl -w net.ipv4.conf.tun0.rp_filter=0
# It won't work without also changing the "all" value
sysctl -w net.ipv4.conf.all.rp_filter=0

Теперь выполните SNAT: iptables -t nat -A POSTROUTING -o tun0 -s 10.0.0.1 -j SNAT - к источнику ip.address.of.your.wlan.interface

Здесь мы меняем адрес источника непосредственно перед тем, как пакеты достигают tun0устройства. tun0.cКод отправляет эти пакеты «как есть» (с измененным адресом источника), и они успешно маршрутизируются через интерфейс WLAN. Но у вас может быть динамический IP на интерфейсе WLAN и вы хотите использовать MASQUERADE(чтобы не указывать адрес интерфейса явно). Вот как вы можете использовать MASQUERADE:

iptables -t nat -A POSTROUTING -o tun0 -s 10.0.0.1 -j SNAT --to-source 10.0.55.1
iptables -t nat -A POSTROUTING -o wlp2s0 -s 10.0.55.1 -j MASQUERADE

Обратите внимание на « 10.0.55.1» IP-адрес - это другое. Вы можете использовать любой IP здесь, это не имеет значения. Пакеты достигают nat/POSTROUTINGцепочки на wlp2s0интерфейсе, если мы изменим исходный IP раньше. И теперь это не зависит от статического IP-адреса для интерфейса WLAN.

ПОДХОД № 3

Вы также можете использовать fwmark. Таким образом , вам не нужно , SNATно вы будете захватывать только исходящие пакеты:
Сначала нужно отключить обратный путь фильтрации для tun0потому что он будет пересылать пакеты , которые принадлежат к другой сети:

sysctl -w net.ipv4.conf.tun0.rp_filter=0
# It won't work without also changing the "all" value
sysctl -w net.ipv4.conf.all.rp_filter=0

Now let's alter the routing rules a bit:
# Delete old rules
ip rule del iif tun0 lookup main
ip rule del from all lookup John

# Packets will start going from wlan interface so they will have source address of it
iptables -t mangle -A OUTPUT -o wlp2s0 -j MARK --set-mark 1
ip rule add fwmark 0x1 lookup John

Это еще один «хак» для маршрутизации и сетевого фильтра, который работает на моем компьютере с Debian 8, но все же я рекомендую использовать первый подход, так как он более естественный и не использует никаких хаков.


Вы также можете рассмотреть возможность создания приложения в качестве прозрачного прокси . Я думаю, что было бы гораздо проще, чем анализировать пакеты с устройства Tun.

tifssoft
источник
Пришлось пользоваться -j SNAT, а не-s SNAT
ильягпетров
Это работает, но производительность очень прерывистая (она может остановиться на 10 секунд, а затем продолжить работу). Я собираюсь понять, почему это происходит и как это исправить.
Ильягпетров
1
Извините, это была моя опечатка. Я добавил другой подход к своему ответу. Понятия не имею о проблеме производительности. Кстати, почему бы не использовать прозрачный прокси-сервер с iptables DNAT для фильтрации и перенаправления трафика?
tifssoft
Я не могу воспроизвести ваш подход к метке, я добавил только sudo ip rule add iif tun0 lookup main priority 500к нему, но все же это не сработало. Мне нравится такой подход, жаль, что я не могу его воспроизвести.
Ильягпетров
1
Спасибо за ваш новый подход, я следовал ему шаг за шагом, и он работал отлично. И все же я не понимаю, зачем нам менять ips, главное, что это работает. В случае провала моих планов с использованием TCP-прокси я смогу вернуться к вашему ответу. Вы показали много сетевых навыков здесь, и я не сомневаюсь, что ваши навыки будут желанными. Удачи!
Ильягпетров