Добавление дополнительных network namespaces к уже настроенным.

Преамбула

Когда-то давно поднимал тему network namespaces (копия), механизма Linux, позволяющего на машине с одним физическим сетевым интерфейсом организовать несколько независимых сетевых стеков, т.е. виртуальных сетевых интерфейсов с разными настройками (IP-адресом, маршрутизацией, правилами IPTABLES и т.д.). Возник вопрос, как к уже настроенным сетевым неймспейсам добавить еще один.

Это не просто, а очень просто.

Итак, имеется система такой вот конфигурации:

А требуется нечто такое:

Добавление дополнительного network namespace’а

1. Создаем новый netspace с именем, например, linkns:

ip netns add linkns

2. Создаем два связанных между собой виртуальных сетевых интерфейса veth2 и veth3:

ip link add veth2 type veth peer name veth3

3. Поднимаем интерфейс veth2, который останется в основном неймспейсе:

ifconfig veth2 0.0.0.0 up

4. Подождали, интерфейс поднялся (для проверки вызываем ifconfig без параметров):

veth2: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        ether 3a:8d:6a:40:b8:38  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

5. Ассоциируем veth3 с новым неймспейсом linkns:

ip link set veth3 netns linkns

6. Добавляем новый интерфейс (veth2) к интерфейсам ранее созданного моста br0

brctl addif <имя_моста> <имя_интерфейса>

brctl addif br0 veth2

Можно проверить список интерфейсов командой:

brctl show br0

Вывод команды:

bridge name     bridge id               STP enabled     interfaces
br0             8000.3a8d6a40b838       no              eth0
                                                        veth0
                                                        veth2

Теперь изначальная схема моста

Превращается в такую:

Включать/отключать физические сетевые интерфейсы или мост не нужно, все было сконфигурированно ранее. Осталось произвести настройки внутри namespace linkns:

1. Поднимаем сетевой интерфейс veth3 внутри неймспейса linkns и присваиваем ему IP.

ip netns exec linkns ifconfig veth3 192.168.0.21 netmask 255.255.255.0

2. Прописываем внутри нетспейса маршрут по умолчанию:

ip netns exec linkns ip route add default via 192.168.0.1 dev veth3 src 192.168.0.21

3. Поднимаем внутри namespace’а loopback-интерфейс:

ip netns exec linkns ifconfig lo 127.0.0.1

4. Если нужно, добавляем файлы конфигурации для namespace’а, например resolv.conf (копия)

5. Проверяем работоспособность неймспейса.

Проверяем сетевые устройства:

ip netns exec linkns ifconfig

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

veth3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.0.21  netmask 255.255.255.0  broadcast 192.168.0.255
        inet6 fe80::8c12:30ff:feda:fe06  prefixlen 64  scopeid 0x20<link>
        ether 8e:12:30:da:fe:06  txqueuelen 1000  (Ethernet)
        RX packets 55  bytes 4391 (4.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 17  bytes 1458 (1.4 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ping:

ip netns exec linkns ping 8.8.8.8

PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=111 time=13.3 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=111 time=11.6 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=111 time=12.0 ms
...

и интернет:

ip netns exec linkns lynx google.com

ФАНФАРЫ!

Network namespeces, resolv.conf и прочие файлы конфигурации.

Когда писал заметку о сетевых неймспейсах, т.е. о том, как на одном компьютере с одной физической сетевой картой организовать несколько виртуальных сетевых интерфейсов с разными IP (копия), забыл упомянуть о маленьком, но важном моменте.

Все созданные виртуальные сетевые стеки, а эмулируется не только сетевая карта, но и весь стек вместе с маршрутизацией, правилами IPTABLES и т.д., можно и нужно по разному конфигурировать. И, естественно, есть возможность создать разные файлы конфигурации для разных namespaces.

Файлы конфигурации хранятся в каталоге /etc/netns/<имя_namespace>

Различный resolv.conf для разных namespace’ов.

Например, в основном неймспейсе есть файл /etc/resolv.conf в котором прописаны адреса DNS для основной системы:

nameserver 10.10.0.1
nameserver 10.10.0.200

И пусть в системе существует второй namespace с именем linkns и для него надо прописать DNS от Google (8.8.8.8 и 8.8.4.4):

1. Создаем каталог /etc/netns/linkns.
2. В каталоге создаем (или копируем готовый из /etc) файл resolv.conf.
3. Записываем в файл новые адреса DNS:

nameserver 8.8.8.8
nameserver 8.8.4.4

Аналогично можно поступить и с другими файлами конфигурации, например правилами IPTABLES (если ваша система поддерживает конфигурацию фаервола через конфигурационные файлы).

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.

Под катом

Скрипт целиком на GitHub