3

В Ubuntu 16.04 я хотел бы направить свой трафик либо через прямой интернет eth0 либо через мой VPN tun0 на основе доменного имени, введенного в браузер. Причина в том, что локальные сайты работают медленно или зависят от местоположения.

Я понимаю, что таблица маршрутизации ядра основана на IP-адресе, а доменные имена обычно разрешаются на программном уровне, но, поскольку linux является платформой, удобной для сценариев, я надеюсь на обходной путь. Хотя я не знаю, как написать такой сценарий.

Итак, я обнаружил, что команда dig example.com +short @8.8.8.8 выведет список IP-адресов, связанных с доменом, и выяснил, что sudo route add -net 8.8.8.8 netmask 255.255.255.255 gw 192.168.2.1 команда пропустит VPN для данного IP (где 192.168.2.1 - это мой eth0 умолчанию). Будет ли кто-нибудь достаточно любезен для создания шаблона скрипта, который читает файл, содержащий доменные имена и вводит правила маршрута при загрузке системы. Бонусные баллы за разрешение маскированных поддоменов *.example.com .

Если для этого безумия есть более простой метод, я приму его в качестве решения.

Примечание: я мог бы очень легко жестко закодировать IP-адреса в /etc/network/interfaces но потом ими стало трудно управлять. Я также попытался жестко запрограммировать в этот файл все известные IP-адреса для моей страны, но он был очень неудачным, наряду с задержкой загрузки.

3 ответа3

8

Маршрутизация на основе целевого домена не является невозможной, и с помощью подходящих инструментов не все так сложно.

Я представлю несколько методов, которые практически не требуют специальной настройки на стороне клиента. Все это предполагает, что вы используете OpenVPN для подключения. Это должно быть достижимо с другими VPN, но может потребовать больше ручной настройки после запуска VPN.

В качестве примера я буду использовать домены "example.com", "us1.example.com", "us2.example.com" и "geoblocked.com" для доменов, которые мы хотим направить через не-VPN интерфейс.

Все команды должны быть запущены от имени пользователя root.

Способ 1 - OpenVPN

Я бы порекомендовал это, только если вы уверены, что IP-адреса, которые вы маршрутизируете, имеют статические IP-адреса, которые никогда не меняются.

Плюсы:

  • Очень просто

Минусы:

  • Надежно только для доменов с IP-адресами, которые никогда не меняются
  • Нужна явная запись для каждого домена и субдомена

Метод:

Добавьте следующие строки в вашу конфигурацию OpenVPN:

route example.com     255.255.255.255 net_gateway
route us1.example.com 255.255.255.255 net_gateway
route us2.example.com 255.255.255.255 net_gateway
route geoblocked.com  255.255.255.255 net_gateway

Перезапустите OpenVPN.

Вот и все, но вам придется перезапустить VPN снова, если эти IP-адреса когда-либо изменятся.

ПРИМЕЧАНИЕ . Некоторые источники сообщают, что вам также необходимо указать allow-pull-fqdn , но, по моему опыту, этого не произошло. YMMV.

Способ 2 - Маршрутизация на основе политик

Маршрутизация на основе политик - это возможность маршрутизации на основе определенных критериев; обычно адрес источника или протокол, но в этом случае мы проверяем имя домена назначения перед маршрутизацией и используем помеченные пакеты ("fwmark").

Сначала нам нужно создать отдельную таблицу для ваших маршрутизируемых VPN-пакетов, чтобы мы могли отмечать те, которые проходят через VPN и пропускают помеченные пакеты через не-VPN-интерфейс. (Имейте в виду, что это один из подходов, и есть много других способов приблизиться к нему, например, позволить VPN делать свою маршрутизацию как обычно через основную таблицу и создавать отдельную таблицу для трафика не-VPN.)

Ваше ядро должно быть достаточно новым и иметь надлежащие модули, хотя современные системы, вероятно, содержат их в своих ядрах по умолчанию.

Имя "vpn_table" (имя таблицы маршрутизации) и числа "201" (идентификатор таблицы маршрутизации) и "3" (fwmark) выбираются произвольно.

Создайте новую таблицу маршрутизации (от имени root):

echo 201 vpn_table >> /etc/iproute2/rt_tables

Настройте OpenVPN:

Создайте где-нибудь следующий скрипт (я называю его «/etc/openvpn/client/setup-routing») и сделайте его исполняемым:

#!/bin/bash
ip route add 0.0.0.0/1 via $route_vpn_gateway dev $dev scope global table vpn_table
ip route add 128.0.0.0/1 via $route_vpn_gateway dev $dev scope global table vpn_table
sysctl -w net.ipv4.conf.$dev.rp_filter=2

# You can optionally leave the next two lines out but run the `ip rule add`
# command at each boot instead
ip rule del fwmark 3 table vpn_table &>/dev/null # This might fail but that's ok
ip rule add fwmark 3 table vpn_table

Переменные в вышеприведенном скрипте будут заполнены OpenVPN как переменные среды. Также обратите внимание, что это устанавливает маршрутизацию ко всем адресам через шлюз VPN в таблице маршрутизации "vpn_table". Если для вашей настройки VPN требуется более сложная маршрутизация, обратитесь к документации OpenVPN и выполните соответствующие настройки.

Добавьте следующее в вашу конфигурацию OpenVPN:

## Policy routing
route-noexec
script-security 2
route-up /etc/openvpn/client/setup-routing

Строка "route-noexec" позволяет OpenVPN извлекать маршрут с сервера, но не позволяет ему фактически заполнять маршруты. Вместо этого вызывается скрипт маршрутизации. «script-security 2» необходим для вызова пользовательского сценария.

Это все, что необходимо для маршрутизации помеченных пакетов, но нам нужно настроить способ их фактической маркировки. Два варианта - использовать dnsmasq с ipset или настроить прокси-сервер squid.

Способ 2a - Маршрутизация на основе политик с использованием ipset и dnsmasq

Я бы порекомендовал этот метод, если вы уже запускаете его на маршрутизаторе на основе dnsmasq или ваши клиенты не поддерживают настройку прокси. По сути, это то же самое, что и кэширующий DNS, который обновляет таблицу маршрутизации при поиске доменного имени.

Плюсы:

  • Управляет поддоменами
  • Работает на устройствах, которые не могут получить доступ к прокси (существуют ли они?)

Минусы:

  • Не обрабатывает поле реферера (см. Метод 2b)
  • Нужны сложные конфиги ipset и iptables
  • Требуется, чтобы система, подключенная по VPN, была настроена в качестве маршрутизатора (необходим выделенный интерфейс)
  • Я понятия не имею, как масштабируемый ipset (мой вариант использования для всего ccTLD)

Это предполагает, что вы уже настроили и настроили dnsmasq и выступаете в качестве шлюза и DNS-сервера для клиентов, подключенных к выделенному интерфейсу "eth1".

Создайте ipset:

ipset create SKIP_VPN_IPSET iphash

Скажите iptables, чтобы пометить пакеты ipset (примечание, это необходимо сделать после создания списка ipset):

# Mark ALL packets coming in on eth1 - change this to the interface dnsmasq listens on
iptables -A PREROUTING -i eth1 -t mangle -j MARK --set-mark 3

# REMOVE mark on any addresses that match our ipset
iptables -A PREROUTING -t mangle -m set --match-set SKIP_VPN_IPSET dst -j MARK --set-mark 0/3

ПРИМЕЧАНИЕ . Приведенные выше команды (ipset и iptables) должны выполняться при каждой загрузке. В качестве альтернативы ваша ОС может предоставлять некоторые параметры для сохранения / восстановления правил iptable и ipsets.

ПРИМЕЧАНИЕ 2: Там задокументировано обратное ! --match-set но в результате все пакеты просто исчезли, когда я попробовал.

Добавьте следующее в ваш dnsmasq.conf:

ipset=/example.com/geoblocked.com/SKIP_VPN_IPSET

Очевидно, настройте эту строку слишком сильно, независимо от того, какие доменные имена вы хотите перенаправить. Это также добавит ВСЕ субдомены в ipset, поэтому вам не нужно явно указывать их. Даже использование TLD будет работать.

Перезапустите dnsmasq и настройте своих клиентов на использование системы, подключенной к VPN, в качестве шлюза и DNS (что следует понимать, если она настроена в качестве сервера DHCP).

Метод 2b - Маршрутизация на основе политик с использованием squid

Это мой любимый метод, и он хорошо работает с моим PS4 и другими устройствами, которые я использую для подключения.

Плюсы:

  • Управляет поддоменами
  • Обрабатывает поле реферера
  • Не требует замены существующего маршрутизатора
  • Клиенты (браузеры) могут по желанию использовать его или нет

Минусы:

  • Клиенты должны поддерживать прокси-соединение

Это предполагает, что у вас есть работающая настройка squid и базовые знания по настройке squid.

Добавьте следующие строки в squid.conf:

# redirect example domains
acl domain_to_remote_proxy dstdomain .example.com
acl ref_to_remote_proxy referer_regex [^.]*\.example.com.*

# redirect geoblocked domain
acl domain_to_remote_proxy dstdomain .geoblocked.com
acl ref_to_remote_proxy referer_regex [^.]*\.geoblocked.com.*

# mark packets that we want routed through the VPN
tcp_outgoing_mark 0x03 !ref_to_remote_proxy !domain_to_remote_proxy

Обратите внимание, что на каждый домен приходится 2 строки, и поддомены совпадают. Первая строка проверяет домен назначения, а вторая соответствует заголовку "Referer". Это полезно, потому что браузеры отправляют реферер при извлечении контента на веб-странице, такой как изображения, CSS или javascript; это означает, что контент, запрашиваемый сайтом, также будет направляться через не-VPN-адрес, даже если он размещен в другом домене (например, example-cdn.com).

На клиентах настройте соединение как обычно, но настройте параметры прокси-сервера, чтобы использовать прокси-сервер и порт для этой системы. Большинство устройств (включая игровые приставки) допускают общесистемную настройку. На ПК большинство браузеров могут быть настроены на использование прокси независимо от настроек системы.

Последнее замечание. Мой вариант использования - для маршрутизации определенных доменов через VPN, а все остальное - без VPN. Методы аналогичны приведенным выше, но инвертированы.

2

Я бы порекомендовал вам избегать управления маршрутизацией на основе доменных имен (кстати, также невозможно разрешить поддомен с подстановочными знаками, будь то бонусные баллы за него или нет:D)

Чтобы быть немного описательным, вы не должны делать это, потому что:

1) некоторые домены время от времени меняют свои IP-адреса,

2) невозможно подобрать подстановочные знаки в поддоменах

3) невозможно узнать / получить все субдомены любого домена

4) любой случайный поддомен может иметь любой случайный IP-адрес.

Таким образом, решение в виде аддона браузера (и / или собственного локального прокси-сервера, такого как squid) - лучший вариант для вашей проблемы.

Но, я полагаю, аддон "FoxyProxy" (изначально аддон Firefox, но AFAIRC, хотя и существует версия Chrome) - это именно то, что вам нужно.

А также, отвечая на ваше уведомление, что «FoxyProxy является платной услугой, и у вас уже есть свой vpn»:

FoxyProxy Plus - платная услуга, но не FoxyProxy.

FoxyProxy - это аддон, доступный для основных браузеров:

Standard Edition (Firefox) | Базовое издание (Firefox)

Standard Edition (Chrom {e, ium}) | Базовое издание (Chrom {e, ium})

Итак, если вы хотите перейти на некоторые домены через VPN, вам следует:

1) написать правила для foxyproxy, чтобы пройти через ваш экземпляр squid для списка доменов

2) и / или написать список правил для squid

3) перехватывать трафик http/https, не принадлежащий squid, с помощью iptables и указывать его на squid по правилу:

iptables -m owner -m multiport -t nat -A OUTPUT ! -o lo ! --uid-owner $squid_user_id -p tcp --dports 80,443,8080,... -j REDIRECT --to-ports $SQUID_PORT

(опция --syn может понадобиться для -p tcp)

4) перехватить http/https-трафик, принадлежащий squid, и пометить его для следующей маршрутизации на VPN с таким правилом:

iptables -A OUTPUT -m owner --uid-owner $squid_user_id -j MARK --set-mark 11

5)

echo 11 forcevpn >> /etc/iproute2/rt_tables
ip rule add fwmark 11 table forcevpn
ip route add default via 10.0.0.1 table forcevpn

где 10.0.0.1 - это ваш шлюз внутри VPN. Или вы можете использовать dev $VPN_IF вместо via 10.0.0.1 если у вас нет шлюза и вы просто хотите передать весь трафик через интерфейс vpn.

6) при желании вам может потребоваться запустить sudo sysctl ipv4.conf.all.rp_filter =0

===

И еще кое-что:

Если вы хотите сделать ту же самую магию с TCP-трафиком, не относящимся к http(s), вам понадобится что-то вроде прокси-цепей, и выполните аналогичную магию захвата.

И, если вы хотите сделать это с UDP, у меня плохие новости: я не знаю ни одного прокси, способного к прокси UDP (из-за природы этого протокола) :)

⇓⇓⇓ РЕДАКТИРОВАТЬ ⇓⇓⇓

В случае, если вам нужна обратная вещь (по умолчанию gw = vpn и вы управляете некоторыми доменами напрямую через ISP), это может быть:

1) написать правила для foxyproxy, чтобы пройти через ваш экземпляр squid для списка доменов

2) захватить трафик, принадлежащий squid, и пометить его для следующей маршрутизации другим способом с помощью правила, подобного этому:

iptables -A OUTPUT -m owner --uid-owner $squid_user_id -j MARK --set-mark 11

3)

echo 11 novpn >> /etc/iproute2/rt_tables
ip rule add fwmark 11 table novpn
ip route add default via ${ISP_GW} table novpn

где ISP_GW - это шлюз, который вы используете для маршрутизации трафика на ваш VPN-сервер. Некоторые пользователи могут захотеть использовать dev ppp0 (или ppp1 , ..., pppN) вместо via ${ISP_GW} в случае, если они используют pptp для подключения к Интернету.

0

Squid не поддерживает socks (например, ssh tunnel)... есть возможность собрать squid с поддержкой socks, но заставить его работать трудно.

Privoxy может сделать работу

  • Поддержка родительских носков
  • Поддержка http/https прокси
  • Реферрер поддержки
  • и т.п.

Настройка Privoxy:

  1. Установите privoxy

  2. Отредактируйте файл конфигурации (удалите все в /etc/privoxy и добавьте /etc/privoxy/config)

    user-manual /usr/share/doc/privoxy/webserver/user-manual
    confdir /etc/privoxy
    logdir /var/log/privoxy
    actionsfile default.action
    filterfile default.filter
    logfile logfile
    toggle  1
    enable-remote-toggle  0
    enable-remote-http-toggle  0
    enable-edit-actions 0
    enforce-blocks 0
    buffer-limit 4096
    enable-proxy-authentication-forwarding 0
    forwarded-connect-retries  0
    accept-intercepted-requests 0
    allow-cgi-request-crunching 0
    split-large-forms 0
    keep-alive-timeout 5
    tolerate-pipelining 1
    socket-timeout 300
    listen-address  127.0.0.1:8888
    forward-socks5 .whatismyipaddress.com 127.0.0.1:8080 . 
    forward-socks5 .whatismyip.com 127.0.0.1:8080 . 
    
  3. Перезапустите сервис

    systemctl start privoxy

  4. Настройка прокси privoxy в клиентском приложении

  5. Если вы хотите также направить реферера, добавьте default.action и default.filter, вы можете проверить это с http://www.play-hookey.com/htmltest/ с помощью HTML-кода.

    <a href="http://amibehindaproxy.com/">test-ip</a></br>
    <a href="http://www.stardrifter.org/cgi-bin/ref.cgi">test-referrer</a>  
    
  6. default.action и default.filter

    default.action

    {+client-header-tagger{referer}}
    /
    
    {+forward-override{forward-socks5 127.0.0.1:8080 .}}
    TAG:.*?hookey.com 
    

    default.filter

    CLIENT-HEADER-TAGGER: referer
    s@^Referer:.*?$@$0@i
    
  7. Перезапустите сервис privoxy

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .