Як змусити весь трафік пройти через один інтерфейс в Linux


12

У мене є власне написаний інтерфейс tun0 (на основі TUN / TAP ), який виводить те, що він отримує.
Мені потрібен весь трафік системи, щоб протікати через цей інтерфейс.
Роль інтерфейсу:

  1. Щоб розібрати пакети, які, ймовірно, будуть піддані цензурі та тунельні.
  2. Передайте весь інший трафік недоторканим.

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

Мені потрібна ваша допомога, щоб показати мені, як зробити весь потік трафіку через самостійно написаний інтерфейс tun0. Якщо tun0 потребує змін, я прошу вас надати такі зміни.

Нижче описано, як я намагався змусити весь трафік пройти через tun0 і не вдався (pings fail).

Складання

  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

Модифіковані джерела з відповіді також тут .

Відповіді:


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а не з вихідним адресою інтерфейсу WLAN (що можна було б очікувати , я думаю). Тому нам потрібно змінити адресу джерела, і це називається джерело 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 це не працює.
Найкращий спосіб усунення несправностей netfilter - це 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 - to-source 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

Це ще один "хак" для маршрутизації та netfilter, який працює на моєму вікні Debian 8, але все ж рекомендую скористатися першим підходом, оскільки він більш природний і не використовує жодних хаків.


Ви також можете створити свою програму як прозорий проксі . Я думаю, що це було б набагато простіше, а не аналізувати пакети з пристрою tun.


Мені довелося користуватися -j SNAT, не-s SNAT
ilyaigpetrov

Це працює, але продуктивність дуже переривчаста (може затриматись протягом 10 секунд, а потім продовжити роботу). Я розберуся, чому це відбувається, і як це виправити.
ilyaigpetrov

1
Вибачте, це був мій друк. Я додав ще один підхід до своєї відповіді. Не майте уявлення про виступ виступу. До речі, чому б не використовувати прозорий проксі з iptables DNAT для фільтрації та перенаправлення трафіку?
tifssoft

Я не в змозі відтворити ваш підхід до позначки, я додав лише sudo ip rule add iif tun0 lookup main priority 500його, але все одно він не працював. Мені подобається такий підхід, шкода, що не можу його відтворити.
ilyaigpetrov

1
Дякую за ваш новий підхід, я дотримувався його крок за кроком, і він працював чудово. Але я не розумію, для чого нам потрібно змінювати ips, головне, що це працює. У випадку, якщо мої плани з проксі-сервером TCP не вдасться, я зможу повернутися до вашої відповіді. Ви продемонстрували тут багато навичок роботи в мережі, і я не сумніваюся, що ваші навички будуть бажані. Удачі!
ilyaigpetrov
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.