Большую часть времени мы используем только самые простые возможности сетевого стека Linux. Маршрут по умолчанию, SNAT, несколько правил netfilter — все, что нужно среднему маршрутизатору. Но есть множество функций для менее распространенных и даже весьма нестандартных ситуаций.
Например, возможность использовать нестандартный широковещательный адрес IPv4 sudo ip addr add 192.0.2.1/24 broadcast 192.0.2.2 dev eth0. Технически ни один RFC этого не запрещает. Я данной возможностью не воспользовался ни разу, но почти уверен, что кто-то нашел ей осмысленное применение.
Dummy interfaces
В отличие от Cisco IOS и систем семейства BSD, в Linux может быть только один loopback interface, который всегда называется lo и несет на себе тот самый адрес 127.0.0.1/8. Если надо просто несколько адресов для разных демонов, можно присвоить их на тот же интерфейс lo.
Но что делать, если требуется несколько независимых локальных интерфейсов?
Некоторые советуют решать эту проблему использованием не по назначению интерфейсов других типов, вроде мостов. Не слушайте их. Правильное решение — использовать интерфейсы типа dummy, которые аналогичны loopback во всем, кроме названия. Исторически так сложилось, что loopback — это уникальный интерфейс lo, и для совместимости сделали отдельный тип.
1 2 3 |
$ ip link add name dum0 type dummy $ ip link set dum0 up $ ip address add 192.0.2.10/32 dev dum0 |
А зачем мне несколько интерфейсов loopback?
На рабочих станциях и серверах обычно такой необходимости нет, но порой удобно иметь независимые интерфейсы для тестирования сетевых приложений. Например, когда нужно посмотреть, как приложение поведет себя, если интерфейс уйдет в down, но создавать ради этого виртуальную машину или отключать реальную сетевую карту не хочется.
Часто эта возможность применяется на маршрутизаторах. У каждого маршрутизатора обычно несколько адресов, в связи с чем возникает проблема выбора основного адреса для управления и для сессий протоколов вроде BGP, которые не используют multicast.
РЕКОМЕНДУЕМ:
Проверка скорости интернет-соединения в терминале Linux
Какой выбрать? Любой интерфейс маршрутизатора потенциально может уйти в down, но сессии BGP и SSH должны работать. Поскольку loopback или dummy самопроизвольно не уйдет в down никогда, можно присвоить ему отдельный адрес и анонсировать его остальной сети через протокол OSPF (Open Shortest Path First), который использует multicast и не зависит от конкретных адресов интерфейсов. В этом случае адрес на loopback останется доступным, если у маршрутизатора есть хотя бы один живой канал в остальную сеть.
MACVLAN
У любого интерфейса L2 может быть один и только один MAC-адрес. Что делать, если надо отправлять кадры с разным MAC-адресом с одного физического интерфейса?
У ядра Linux на это есть ответ, и тип таких интерфейсов называется macvlan. Создать и поднять его можно следующими командами:
1 2 |
$ sudo ip link add name macvlan0 link eth0 type macvlan $ sudo ip link macvlan0 up |
В опции link мы указываем родительский физический интерфейс. По умолчанию используется случайный MAC-адрес, но ничто не мешает присвоить любой другой командой ip link set dev macvlan0 address <some MAC>.
Посмотрим на статус нового интерфейса:
1 2 3 |
$ ip li sh macvlan0 3: macvlan0@eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether 8a:01:12:8f:1f:7c brd ff:ff:ff:ff:ff:ff |
Если присвоить нашему виртуальному интерфейсу адрес из сети 203.0.113.0/24, можно увидеть, что весь трафик в эту сеть отправляется с MAC-адреса от macvlan0, а не родительского eth0.
1 2 3 4 5 |
$ ip address add 203.0.113.90/25 dev macvlan0 $ tcpdump -eni eth0 dst 203.0.113.1 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 20:49:21.988045 8a:01:12:8f:1f:7c > Broadcast, ethertype ARP (0x0806), length 42: Request who-has 203.0.113.1 tell 203.0.113.90, length 28 |
Зеркалирование трафика
Зеркалирование и перенаправление обычно организуют на коммутаторах. Но если нужно сделать это на сервере или маршрутизаторе с Linux, никто не запретит.
Правила зеркалирования создаются с помощью tc. Мы рассмотрим только простейший случай: готовый рецепт для зеркалирования с dum0 на dum1 (интерфейсы можно подставить любые):
1 2 3 4 5 |
$ tc qdisc add dev dum0 ingress $ tc filter add dev dum0 parent ffff: protocol all u32 match u8 0 0 action mirred egress mirror dev dum1 $ tc qdisc add dev dum0 handle 1: root prio $ tc filter add dev dum0 parent 1: protocol all u32 match u8 0 0 action mirred egress mirror dev dum1 |
Опция mirred дает возможность как копировать, так и перенаправлять пакеты с одного интерфейса на другой. В сочетании с классификаторами трафика из tc можно настроить самые разные сценарии, от зеркалирования только определенного трафика до отправки трафика сверх определенной полосы пропускания на другой интерфейс.
Маршруты blackhole
С помощью маршрутов можно не только отправить пакеты на определенный шлюз, но и просто избавиться от ненужных пакетов. Маршрутизация срабатывает до межсетевого экрана, и проверка адреса выполняется быстрее.
РЕКОМЕНДУЕМ:
Аналоги Microsoft Office для Linux
Зараженные хосты шлют трафик к контроллеру ботнета по адресу 192.0.2.10? Просто добавьте такой маршрут:
1 |
$ ip route add blackhole 192.0.2.10/32 |
Теперь трафик к 192.0.2.10 ядро будет сразу отправлять в /dev/null. Кроме blackhole, есть и другие виды маршрутов, которые отличаются действиями ядра. Их можно использовать, чтобы точнее сообщить клиенту, что происходит, или для эмуляции разных ситуаций в сети.
- blackhole — уничтожить пакет и ничего не делать;
- prohibit — уничтожить пакет и отправить клиенту ICMP host prohibited;
- unreachable — уничтожить пакет и отправить клиенту ICMP host unreachable;
- throw — уничтожить пакет и отправить клиенту ICMP net unreachable.
В маршрутизаторах BGP у маршрутов blackhole есть и более интересное применение, но это другая история.
Группы интерфейсов
Возможность работать с диапазонами портов — привычное дело для пользователей управляемых коммутаторов. Для тех, кто скучает по этой возможности в Linux, такая функциональность есть в iproute2.
Неудобство состоит в том, что интерфейсы нужно добавлять в группы по одному, командой ip link set <intf> group <number>. Номер группы должен быть в диапазоне от 1 до 255, по умолчанию интерфейсы принадлежат группе 0.
Создадим пару интерфейсов dummy и добавим их в группу номер 10:
1 2 3 4 |
$ ip link add name dum0 type dummy $ ip link add name dum1 type dummy $ ip link set dum0 group 10 $ ip link set dum1 group 10 |
Как обычно, интерфейсы создаются в выключенном состоянии:
1 2 3 4 5 |
$ ip link show group 10 4: dum0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group 10 qlen 1000 link/ether 22:b4:dc:27:2f:6d brd ff:ff:ff:ff:ff:ff 5: dum1: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group 10 qlen 1000 link/ether 5a:da:93:ab:9d:a7 brd ff:ff:ff:ff:ff:ff |
Теперь мы можем включить их все сразу:
1 2 3 4 5 6 |
$ sudo ip link set group 10 up $ ip link show group 10 4: dum0: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN mode DEFAULT group 10 qlen 1000 link/ether 22:b4:dc:27:2f:6d brd ff:ff:ff:ff:ff:ff 5: dum1: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN mode DEFAULT group 10 qlen 1000 link/ether 5a:da:93:ab:9d:a7 brd ff:ff:ff:ff:ff:ff |
К сожалению, простого способа увидеть список групп в Linux нет. Зато есть возможность присвоить группам понятные человеку имена. Соответствие номеров и имен хранится в файле /etc/iproute2/group.
По умолчанию там определена только группа 0, новые записи легко добавить по аналогии:
1 2 3 |
$ cat /etc/iproute2/group # device group names 0 default |
Больше символьных имен
Кроме групп интерфейсов, присвоить символьные имена можно и другим объектам. В /etc/iproute2/ найдутся файлы настроек для разных целей.
Например, если вы используете policy-based routing, можно присвоить имена таблицам маршрутизации, добавив записи в /etc/iproute2/rt_tables:
1 2 |
$ echo "10 cheap_isp" >> /etc/iproute2/rt_tables $ echo "20 good_isp" >> /etc/iproute2/rt_tables |
Поточное выполнение команд iproute2
Все давно привыкли к iptables-save и iptables-restore, но вот команды ip очень часто так и вводят по одной даже в скриптах.
Между тем там давно существует опция -batch, которая позволяет читать команды из файла. Писать ip в командах внутри файла не нужно. Вот так можно было бы автоматизировать создание интерфейсов dummy из предыдущих пунктов:
1 2 3 4 5 6 7 |
$ cat /tmp/dummy-intfs link add dum0 type dummy link add dum1 type dummy link set dum0 up link set dum1 up $ ip -batch /tmp/dummy-intfs |
Машиночитаемый вывод информации
Если вы все еще парсите вывод ifconfig в скриптах и при этом нецензурно ругаетесь, у меня для вас хорошие новости: у iproute2 имеются опции, которые позволят вам и вашим коллегам наконец взять детей на работу.
Можно получить вывод либо в традиционном для UNIX формате из полей с разделителями, либо в JSON.
Опция --brief ( -br) идеальна для разбора с помощью cut или awk -F' ' и отлично подойдет для применения в традиционных скриптах Shell:
1 2 3 4 5 |
$ ip --brief link show macvlan0 macvlan0@eth0 UP 8a:01:12:8f:1f:7c <BROADCAST,MULTICAST,UP,LOWER_UP> $ ip --brief address show macvlan0 macvlan0@eth0 UP 203.0.113.90/25 fe80::8801:12ff:fe8f:1f7c/64 |
Если адресов у интерфейса несколько, они все будут выведены через пробел после состояния интерфейса, сначала IPv4, затем IPv6.
Вывод в JSON
Если вы решили порвать с прошлым и пишете скрипты, к примеру, на Python, вывод в JSON может быть предпочтительнее.
Эта возможность в iproute2 появилась недавно (с версии 4.13) и имеет ряд особенностей, граничащих с багами. Надеюсь, их исправят в следующих версиях.
Важный момент: опции --json и --brief не взаимоисключающие. Их можно указать одновременно, в этом случае вывод будет менее детальным.
Посмотрим на пример вывода для ip address show:
1 |
$ ip --json --brief address show macvlan0 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
[ {},{}, { "link": "eth0", "ifname": "macvlan0", "operstate": "UP", "addr_info": [ { "local": "203.0.113.90", "prefixlen": 25 }, { "local": "203.0.113.91", "prefixlen": 25 }, { "local": "fe80::8801:12ff:fe8f:1f7c", "prefixlen": 64 } ] }, {},{},{},{},{},{} ] |
Несколько неудобно, что мы получаем не ассоциативный массив с именем интерфейса в качестве индекса, а обычный массив с объектами внутри. Более того, если отфильтровать вывод, указав имя интересующего интерфейса, на месте непоказанных интерфейсов будут пустые значения, которые придется отфильтровывать самому.
Тем не менее вывод не подвержен ошибкам разбора, предоставляет большое количество информации (особенно без --brief) и не слишком сложен в работе, хотя простор для улучшений явно есть.
РЕКОМЕНДУЕМ:
Аналоги Bash Unix инструментов в PowerShell Windows
Заключение
Надеюсь, эти возможности помогут вам успешно настроить и отладить вашу Linux сеть и при этом сэкономить время. Если не нашли нужное, не забывайте смотреть в документацию — почти наверняка что-нибудь для вашей ситуации там отыщется.