Differences between revisions 1 and 2
Revision 1 as of 2022-04-27 22:47:29
Size: 4568
Editor: FrBrGeorge
Comment:
Revision 2 as of 2022-04-28 10:20:28
Size: 11310
Editor: FrBrGeorge
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
= Тунелирование и частные сети =

'''TODO'''


-----

склад:

== настройка IPIP ==

сервер:
= Туннелирование и частные сети =

'''Туннелирование''': использование некоторого потока данных для инкапсуляции (в общем случае — произвольного) сетевого трафика.
 * Шифрование контента
 * Защита от пассивного анализа / фильтрации
 * Платформа для включения в инфраструктуру (частные и программно определяемые сети)

== Простейший туннель: IP over IP ==

[[WP:IP_in_IP]]
 * Просто добавим `ip link` соответствующего типа
  * С указанием реальных адресов концов туннеля
 * Настроим IP как обычно)
 * [[https://developers.redhat.com/blog/2019/05/17/an-introduction-to-linux-virtual-interfaces-tunnels#ipip|Пример на developers.redhat.com]]
=== Использование ===
Старая схема:
 * '''клиент''' ← очень-внутренняя-сеть → '''маршрутизатор''' ← внутренняя-сеть → '''сервер''' → интернеты

'''Сервер''':
 * Настроим «выход в интернет»
 * NAT сделаем сами примерно так:
Line 16: Line 25:
                type nat hook postrouting priority srcnat + 1; policy accept;
                ip saddr 10.0.0.0/8 oif "eth0" masquerade # для всех сетей
                type nat hook postrouting priority srcnat; policy accept;
                ip saddr 10.0.0.0/8 oif "eth0" masquerade
Line 20: Line 29:

# ip tunnel add hole mode ipip remote 10.2.2.1 local 10.1.1.1
}}}
 * Для краткости воспользуемся `ip tunnel`
{{{

# ip tunnel add hole mode ipip remote IP-клиента local наш-IP
Line 23: Line 34:
# ip addr add dev hole 10.10.10.1/24
# + интернет и внутренняя сеть 10.1.1/24

# в настройках внутренней сети
# ip addr add dev hole адрес-туннеля/24
}}}
 * Все адреса — и туннеля, и «настоящие» пускай лежат в 10/8

Помните, как в отсутствие OSFP мы ручками настраивали информацию о всех внутренних сетях? В файле `внутренняя_сеть.network` это выглядит так:
{{{
… настройки внутренней сети …


Line 28: Line 45:
Destination=10.2.2.0/24
Gateway=10.1.1.2

}}}

роутер:
{{{
две сети 10.2.2/24 и 10.1.1/24

запрет TCP (потом):
Destination=очень-внутренняя-сеть-с-клиентом/24
Gateway=ближайший-маршрутизатор
}}}

Маршрутизатор:
 * Просто две сети и маршрутизация
 * Когда будем тестировать туннель, включим nft и добавим туда
{{{
Line 41: Line 56:
клиент:
{{{
сеть 10.2.2.1
}}}

подключаем ipip
{{{
# так же, как на сервере, только меняем local и remote ☺
# IP 10.10.10.2
ping 10.10.10.1
}}}

См. на MTU: мы же запихнули IP в IP ☺

смотрим на router пакеты в туннеле;

{{{
# date | netcat ya.ru 80 — (всё ещё работает по-старому)
}}}
'''Клиент''':
 * Для начала просто настроим очень-внутреннюю сеть.
 * Туннель настаиваем так же, как на сервере, только меняем local и remote ☺

Должно работать:
 * Ping адрес того конца туннеля
 * См. на MTU: мы же запихнули IP в IP ☺
 * смотрим на router пакеты в туннеле;
Line 67: Line 71:

Проблема превращения старого маршрута в маршрут до tunnel endpoint

запрещаем на router tcp
На клиненте:
{{{
# date | netcat ya.ru 80 — (всё ещё работает по-старому)
}}}
 * всё ещё работает по-старому, это же только туннель между двумя хостами

Проблема превращения старого маршрута в маршрут до tunnel endpoint:
 * Если тупо задать маршрут по умолчанию через туннель, то как будут ходить пакеты самого туннеля?

Простая реализация:
 * Для тестов запрещаем весь проходящий TCP на маршрутизаторе (см выше)
Line 73: Line 84:

* добавляем 1:1 маршрут через router на server (бывший default router)
 * добавляем 1:1 (/32→/32) маршрут через router на server (бывший default router)
Line 76: Line 86:
 * добавляем default route через 10.10.10.1  * добавляем default route через конец туннеля
Line 81: Line 91:
всё по [[man8:ip-l2tp]] с инкапсуляцией в UDP Всё по [[man8:ip-l2tp]] с инкапсуляцией в UDP и для простоты без bridge

'''TODO''' скопипастить этот кусок сюда
Line 88: Line 100:
Главная фишка, если применять bridge («Configure as bridged interfaces» в man-е): на сервере интерфейс ''один'' и IP у него тоже один. Главная фишка: если применять bridge («Configure as bridged interfaces» в man-е): на сервере интерфейс ''один'' и IP у него тоже один.

=== Использование ===

(если успеем, то тупо пример из MAN)
Line 93: Line 109:

{{{
# wg genkey | tee /dev/stderr | wg pubkey # для копипасты
}}}
 * Идея та же самая: UDP-пакеты с каким-то payload
 * Защита асимметричным шифрованием
  * нужны пары откытый/закрытый ключ от всех участников процесса — и от сервера, и от клиентов
  * дополнительно можно ключ защитить паролем
  * обычно генерирует и раздаёт админ
 * Есть клиенты по всякие архитектуры
Лайфхак:
 * Для копипасты:
 {{{
# wg genkey | tee /dev/stderr | wg pubkey
 }}}
Line 100: Line 123:
сервер: '''Сервер''':
Line 109: Line 132:
                           возможно, лучше PrivateKeyFile =
70-wg.netdev:# PublicKey   = сервера, просто лежит тут прозапас
                           (возможно, лучше PrivateKeyFile = …)
70-wg.netdev:# PublicKey = сервера, просто лежит тут прозапас
Line 123: Line 146:
Клиент: '''Клиент''':
Line 144: Line 167:
=== Частная сеть как выход в интернет ===

Ещё раз: проблема превращения старого маршрута в маршрут до tunnel endpoint

Задача довольно просто формулируется, но полна нюансов:

 * При внезапном перенаправлении всего роутинга в в туннель надо умудриться не направить туда роутинг до end point-а.
 * Нюанс № 0: любые нелокальные маршруты, про которые знает внутренний маршрутизатор, но не знает endpoint. Например, локальный DNS-сервер с внутренним DNS-ом.

В нашем случае довольно просто, ибо статика:

Сервер:
 * Добавим частную подсеть в NAT
Клиент:
 * Добавим ''явный'' маршрут до сервера частной сети через тот же маршрутизатор, что и по умолчанию
 * Добавим ещё явных маршрутов до ключевых локальных сервисов (DNS, файлопомойка, корпоративный мессенджер, whatever)
 * ''Только после этого'' выставим маршрутизатор по умолчанию (в нашем случае статика, поэтому без разницы) на сервер частной сети
  * При этом либо удаляем старый маршрут по умолчанию, либо делаем так, чтобы метрика новой записи была выше (параметр `metric число` команды `ip route add` или `Metric=` в секции `[Route]` файла `.network`).
Нюансы:
 * Хорошо, если все важные маршруты можно описать просто большим диапазоном (у нас 10/8) — а ну как нельзя?
 * Или, что хуже, у админов нет фантазии, и ''обе'' сети — и локальная, и частная — это `192.168.0.0/24`?
 * Манипуляции с метрикой надо делать над ''исходным'' маршрутом, никак не связанным с частной сетью
 * Манипуляции с удалением и добавлением маршрутов — это вообще контекстно-зависимый ад
 * [[https://github.com/WireGuard/wireguard-tools/blob/master/src/wg-quick/linux.bash|wg-quick]] ''как-то'' решает эту проблему.

⇒ Нужен разумный best practice. Для начала хотя бы сделать в ядре метрику по умолчанию не 0…

А ещё вот:

https://lists.zx2c4.com/pipermail/wireguard/2022-January/007403.html

== Рашн ВПН ==



=== Всякое ===
 * [[RW:IPsec]] — безудержно. Но работает!
  * Основная фишка: транспортный режим, в котором шифруется только payload от IP…
   * …идея была в том, чтобы логика сети оставалась, а в пакеты никто не заглядывал…
   * …и она оказалась провальной: даже NAT не работает
  * Тогда придумали туннельный режим. А он как всё такие туннели, только сложнее в поддержке.
 * [[https://openvpn.net|OpenVPN]]
  * Если не wireguard, то !OpenVPN — давно и проверенно работает
 * https://github.com/tonarino/innernet
 * … тысячи их

== Д/З ==
Line 145: Line 216:

Таки проблема превращения старого маршрута в маршрут до tunnel endpoint

https://lists.zx2c4.com/pipermail/wireguard/2022-January/007403.html

=== Всякое ===
 * https://github.com/tonarino/innernet
 * [[https://github.com/WireGuard/wireguard-tools/blob/master/src/wg-quick/linux.bash|wg-quick]]
 * … тысячи их
 * [[https://openvpn.net|OpenVPN]]

Туннелирование и частные сети

Туннелирование: использование некоторого потока данных для инкапсуляции (в общем случае — произвольного) сетевого трафика.

  • Шифрование контента
  • Защита от пассивного анализа / фильтрации
  • Платформа для включения в инфраструктуру (частные и программно определяемые сети)

Простейший туннель: IP over IP

IP_in_IP

  • Просто добавим ip link соответствующего типа

    • С указанием реальных адресов концов туннеля
  • Настроим IP как обычно)
  • Пример на developers.redhat.com

Использование

Старая схема:

  • клиент ← очень-внутренняя-сеть → маршрутизатор ← внутренняя-сеть → сервер → интернеты

Сервер:

  • Настроим «выход в интернет»
  • NAT сделаем сами примерно так:

table ip nat {
        chain postrouting {
                type nat hook postrouting priority srcnat; policy accept;
                ip saddr 10.0.0.0/8 oif "eth0" masquerade
        }
}
  • Для краткости воспользуемся ip tunnel

# ip tunnel add hole mode ipip remote IP-клиента local наш-IP
# ip l set hole up
# ip addr add dev hole адрес-туннеля/24
  • Все адреса — и туннеля, и «настоящие» пускай лежат в 10/8

Помните, как в отсутствие OSFP мы ручками настраивали информацию о всех внутренних сетях? В файле внутренняя_сеть.network это выглядит так:

… настройки внутренней сети …


[Route]
Destination=очень-внутренняя-сеть-с-клиентом/24
Gateway=ближайший-маршрутизатор

Маршрутизатор:

  • Просто две сети и маршрутизация
  • Когда будем тестировать туннель, включим nft и добавим туда

# nft add rule inet filter forward ip protocol tcp reject

Клиент:

  • Для начала просто настроим очень-внутреннюю сеть.
  • Туннель настаиваем так же, как на сервере, только меняем local и remote ☺

Должно работать:

  • Ping адрес того конца туннеля
  • См. на MTU: мы же запихнули IP в IP ☺
  • смотрим на router пакеты в туннеле;

Вот уже почти VPN!

  • на сервере — по интерфейсу для каждого клиента ☹, и что хуже — по паре IP-адресов. Если клментов много, этих IP-адресову него будет…

    • ⇒ для p2p
  • нет шифрования и авторизации

Туннель как маршрут по умолчанию

На клиненте:

# date | netcat ya.ru 80 — (всё ещё работает по-старому)
  • всё ещё работает по-старому, это же только туннель между двумя хостами

Проблема превращения старого маршрута в маршрут до tunnel endpoint:

  • Если тупо задать маршрут по умолчанию через туннель, то как будут ходить пакеты самого туннеля?

Простая реализация:

  • Для тестов запрещаем весь проходящий TCP на маршрутизаторе (см выше)

DNS (через UDP) работает, netcat ya.ru 80 — нет

  • добавляем 1:1 (/32→/32) маршрут через router на server (бывший default router)
  • удаляем default route
  • добавляем default route через конец туннеля
  • netcat ya.ru 80 — работает!

l2tp — фреймы в IP

Всё по ip-l2tp с инкапсуляцией в UDP и для простоты без bridge

TODO скопипастить этот кусок сюда

# ip l2tp show tunnel
# ip l2tp show session

Главная фишка: если применять bridge («Configure as bridged interfaces» в man-е): на сервере интерфейс один и IP у него тоже один.

Использование

(если успеем, то тупо пример из MAN)

Wireguard

Сайт, и конечно Arch-вики

  • Идея та же самая: UDP-пакеты с каким-то payload
  • Защита асимметричным шифрованием
    • нужны пары откытый/закрытый ключ от всех участников процесса — и от сервера, и от клиентов
    • дополнительно можно ключ защитить паролем
    • обычно генерирует и раздаёт админ
  • Есть клиенты по всякие архитектуры

Лайфхак:

  • Для копипасты:
    # wg genkey | tee /dev/stderr | wg pubkey

Минимальная настройка:

Сервер:

70-wg.netdev:[NetDev]
70-wg.netdev:Name        = wg
70-wg.netdev:Kind        = wireguard
70-wg.netdev:
70-wg.netdev:[WireGuard]
70-wg.netdev:ListenPort  = 51820
70-wg.netdev:PrivateKey  = сервера, никому не показывать
                           (возможно, лучше  PrivateKeyFile = …)
70-wg.netdev:# PublicKey = сервера, просто лежит тут прозапас
70-wg.netdev:
70-wg.netdev:[WireGuardPeer]
70-wg.netdev:AllowedIPs  = 192.168.111.0/24
70-wg.netdev:PublicKey   = клиента

70-wg.network:[Match]
70-wg.network:Name        = wg
70-wg.network:
70-wg.network:[Network]
70-wg.network:Address     = 192.168.111.1/24

Клиент:

90-wg.netdev:[NetDev]
90-wg.netdev:Name        = wg
90-wg.netdev:Kind        = wireguard
90-wg.netdev:
90-wg.netdev:[WireGuard]
90-wg.netdev:PrivateKey  = этого клиента
90-wg.netdev:# PublicKey   = этого клиента, прозапас
90-wg.netdev:
90-wg.netdev:[WireGuardPeer]
90-wg.netdev:AllowedIPs  = 192.168.111.0/24
90-wg.netdev:PublicKey   = сервера
90-wg.netdev:Endpoint    = 10.1.1.1:51820
90-wg.network:[Match]
90-wg.network:Name        = wg
90-wg.network:
90-wg.network:[Network]
90-wg.network:Address     = 192.168.111.5/24

Частная сеть как выход в интернет

Ещё раз: проблема превращения старого маршрута в маршрут до tunnel endpoint

Задача довольно просто формулируется, но полна нюансов:

  • При внезапном перенаправлении всего роутинга в в туннель надо умудриться не направить туда роутинг до end point-а.
  • Нюанс № 0: любые нелокальные маршруты, про которые знает внутренний маршрутизатор, но не знает endpoint. Например, локальный DNS-сервер с внутренним DNS-ом.

В нашем случае довольно просто, ибо статика:

Сервер:

  • Добавим частную подсеть в NAT

Клиент:

  • Добавим явный маршрут до сервера частной сети через тот же маршрутизатор, что и по умолчанию

  • Добавим ещё явных маршрутов до ключевых локальных сервисов (DNS, файлопомойка, корпоративный мессенджер, whatever)
  • Только после этого выставим маршрутизатор по умолчанию (в нашем случае статика, поэтому без разницы) на сервер частной сети

    • При этом либо удаляем старый маршрут по умолчанию, либо делаем так, чтобы метрика новой записи была выше (параметр metric число команды ip route add или Metric= в секции [Route] файла .network).

Нюансы:

  • Хорошо, если все важные маршруты можно описать просто большим диапазоном (у нас 10/8) — а ну как нельзя?
  • Или, что хуже, у админов нет фантазии, и обе сети — и локальная, и частная — это 192.168.0.0/24?

  • Манипуляции с метрикой надо делать над исходным маршрутом, никак не связанным с частной сетью

  • Манипуляции с удалением и добавлением маршрутов — это вообще контекстно-зависимый ад
  • wg-quick как-то решает эту проблему.

⇒ Нужен разумный best practice. Для начала хотя бы сделать в ядре метрику по умолчанию не 0…

А ещё вот:

https://lists.zx2c4.com/pipermail/wireguard/2022-January/007403.html

Рашн ВПН

Всякое

  • IPsec — безудержно. Но работает!

    • Основная фишка: транспортный режим, в котором шифруется только payload от IP…
      • …идея была в том, чтобы логика сети оставалась, а в пакеты никто не заглядывал…
      • …и она оказалась провальной: даже NAT не работает
    • Тогда придумали туннельный режим. А он как всё такие туннели, только сложнее в поддержке.
  • OpenVPN

    • Если не wireguard, то !OpenVPN — давно и проверенно работает
  • https://github.com/tonarino/innernet

  • … тысячи их

Д/З

TODO

LecturesCMC/LinuxNetwork2022/11_TunnelingVPN (last edited 2022-05-16 10:26:44 by FrBrGeorge)