Network namespaces или несколько виртуальных сетевых карт (интерфейсов) с разными IP на одной машине
С одной физической сетевой картой.
Например мы хотим организовать следующую схему:
1. После запуска сервер устанавливает соединение с VPN-провайдером, и весь трафик идет через VPN.
2. Некоторым программам VPN не нужен, пусть это например будут TOR, I2P (у них и так шифрование, плюс им бы желательно скорость работы повыше, а напрямую соединяться быстрее, чем через VPN). Плюс, например, мы хотим ходить на некоторые сайты в обход VPN, либо иметь возможность запускать в обход VPN какие-либо трафикоемкие программы, например торрент-клиент. Ну пусть еще будет отдельный локальный сервис, например FTP, также висящий на отдельном IP.
Как.
В Linux есть замечательный механизм network namespaces, который на одной машине позволяет создать несколько изолированных друг от друга сетевых подсистем, почти как сеть в виртуальной машине. Не бойтесь, все делается на уровне ядра, потому тормозов, характерных для виртуальных машин не будет. И пусть слово "изолированных" вас тоже не пугает, когда надо - изолированных, а когда надо - мы их свяжем.
Эмулируется полностью сетевой стек: сетевые интерфейсы, таблица маршрутизации, файрволл и т.д. Так, как это работает на уровне ядра и для определенных процессов, то вполне можно получить рабочую конфигурации, когда на одной машине есть несколько сетевых интерфейсов с одинаковыми IP-адресами и ничто не конфликтует.
Поскольку в процессе нам придется поднимать/опускать физические и виртуальные сетевые карты, настоятельно советую отключить Network Manager, а основную сеть настроить вручную. С включенным Network Manager может ничего не получиться, т.к. он в самый ответственный момент влезет и напоганит в конфигурации.
Как на Slackware отключить Network Manager и настроить сеть вручную (копия)
Конфигурация namespace'ов производится с помощью iproute2.
1. Создаем новый неймспейс с именем
provns
:ip netns add provns
2. Создаем две связанных между собой виртуальных сетевых карты (интерфейса)
ip link add veth0 type veth peer name veth1
3. Поднимаем интерфейс
veth0
:ifconfig veth0 0.0.0.0 up
4. Ассоциируем вторую виртуальную карту с созданным нэймспейсом:
ip link set veth1 netns provns
Получился один дополнительный namespace, связанный с основным виртуальными сетевыми интерфейсами
veth0
и veth1
.Теперь надо связать виртуальный интерфейс
veth0
с физической сетевой картой (интерфейсом) eth0
. Сделать это можно разными способами, например, присвоить интерфейсам разные IP-адреса из разных подсетей и сделать маскарадинг с помощью IPTABLES, а можно воспользоваться мостами.Мост - специальное сетевое устройство (в данном случае не физическое, а логическое) позволяющее связать два (и более) сетевых интерфейса на канальном уровне, как в маршрутизаторе.
Подробнее про мосты:
- Linux Bridge
- Виртуальные сетевые устройства в Linux: Linux Bridge
- 10 примеров команды brctl в Linux для сетевого Ethernet моста
- Эти статьи в PDF
Итак:
5. Отключаем физический интерфейс
eth0
:ifconfig eth0 down
6. Включаем его, но IP-адрес не присваиваем (IP-адрес будет присвоен мосту):
ifconfig eth0 0.0.0.0 up
7. Создаем мост
br0
:brctl addbr br0
8. Соединяем (добавляем интерфейсы к мосту)
eth0
и veth0
:brctl addif br0 eth0 veth0
9. Поднимаем (включаем) мост, присваивая ему IP-адрес и маску подсети:
ifconfig br0 192.168.0.15 netmask 255.255.255.0 up
Получилось как на схеме:
10. Устанавливаем маршрут по умолчанию в основном namespace:
ip route add default via 192.168.0.1 dev br0 src 192.168.0.15
Далее конфигурируем namespace:
Выполнение любых команд в указанном namespace производится командой
ip netns exec <имя_namespace> <команда> [параметры_команды]
Например, если мы хотим выполнить
ifconfig
в namespace с именем provns
, то команда будет:ip netns exec provns ifconfig
11. Поднимаем (включаем) сетевой интерфейс
veth1
внутри нэймспейса provns
, и присваиваем ему адрес 192.168.0.20
:ip netns exec provns ifconfig veth1 192.168.0.20 netmask 255.255.255.0
12. Прописываем внутри нэймспейса маршрут по умолчанию:
ip netns exec provns ip route add default via 192.168.0.1 dev veth1 src 192.168.0.20
13. Поднимаем внутри namespace'а loopback-интерфейс:
ip netns exec provns ifconfig lo 127.0.0.1
Поскольку на включение/выключение сетевых устройств требуется время (немного, но требуется), то если автоматизировать создание и настройку namespaces в скрипте, что я и буду делать, то потребуется как-то контролировать, поднялось/опустилось ли то или иное сетевое устройство.
Для такой задачи есть скрипт
ndstatus
, который можно взять здесь Описание скрипта (копия). Положите его в каталог где будет скрипт, настраивающий namespaces.В самом скрипте настройки namespaces заводим функцию
wait_to()
, которая будет выводить уведомление на экран, раз в секунду вызывать скрипт ndstatus
и проверять статус сетевого устройства. Если он изменился на указанный при вызове функции, то функция передает управление далее, если нет - отсчитывает время, а если вышло максимальное время, указанное в параметрах функции (при вызове), значит что-то пошло не так, функция уведомляет об ошибке.wait_to()
{
L_MESS=$1
L_DEV=$2
L_ST=$3
L_TIME=$4
L_NS=$5
L_LOOP=0
L_RETCODE=666
echo -n $L_MESS
while [ $L_LOOP -eq 0 ];do
echo -n "."
if [ -z $L_NS ]; then
./ndstatus $L_DEV -s
L_RETCODE=$?
else
ip netns exec $L_NS ./ndstatus $L_DEV -s
L_RETCODE=$?
fi
if [[ "$L_ST"=="up" ]]; then
if [ $L_RETCODE -eq 0 ]; then
L_LOOP=1
echo
fi
fi
if [[ "$L_ST"=="down" ]]; then
if [ $L_RETCODE -eq 1 ]; then
L_LOOP=1
echo
fi
fi
sleep 1
let L_TIME=L_TIME-1
if [ $L_TIME -lt 0 ]; then
echo
echo "Oops, something wrong..."
sleep 10
L_LOOP=1
fi
done
}
В остальном, скрипт делает то же самое, что было описано выше, только после команд включения/выключения сетевых устройств вызывается функция
wait_to()
echo "Adding namespace..."
ip netns add provns
echo "Configure virtual network card..."
ip link add veth0 type veth peer name veth1
ifconfig veth0 0.0.0.0 up
ip link set veth1 netns provns
ifconfig eth0 down
wait_to "Down network card..." eth0 down 5
ifconfig eth0 0.0.0.0 up
wait_to "Up network card..." eth0 up 5
echo "Configure bridge..."
brctl addbr br0
brctl addif br0 eth0 veth0
ifconfig br0 192.168.0.15 netmask 255.255.255.0 up
wait_to "Up bridge..." br0 up 7
#echo "Delete default route..."
#ip route del default
echo "Add default route..."
ip route add default via 192.168.0.1 dev br0 src 192.168.0.15
ip netns exec provns ifconfig veth1 192.168.0.20 netmask 255.255.255.0
wait_to "Configure namespace. Up virtual network card..." veth1 up 5 provns
echo "Set default route for namespace..."
ip netns exec provns ip route add default via 192.168.0.1 dev veth1 src 192.168.0.20
echo "Configure lo interface..."
ip netns exec provns ifconfig lo 127.0.0.1
echo "Network namespace configured!"
Скрипт целиком на GitHub
Это репост с сайта http://tolik-punkoff.com
Оригинал: http://tolik-punkoff.com/2019/11/24/netw