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 и настроить сеть вручную (копия)

Создание и конфигурация network namespace.

Конфигурация 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

Скрипт для автоматизации настройки network namespace.

Поскольку на включение/выключение сетевых устройств требуется время (немного, но требуется), то если автоматизировать создание и настройку 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

2 Responses to Network namespaces или несколько виртуальных сетевых карт (интерфейсов) с разными IP на одной машине.

  1. Pingback: Network namespeces, resolv.conf и прочие файлы конфигурации. | Персональный блог Толика Панкова

  2. Pingback: Добавление дополнительных network namespaces к уже настроенным. | Персональный блог Толика Панкова

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *