Что такое встроенная сеть (embedded network)? Мне довольно сложно было найти подходящее название для этого явления, но я очень часто с ним сталкивался, и поэтому придумал своё. Хорошим примером может служить портативная видеостойка. Допустим, вы таскаете стойку с видео- и сетевым оборудованием, и вам нужно подключать её к сети на месте проведения мероприятия для стриминга в Интернет. Устройства в стойке должны общаться друг с другом, но вы не хотите заново конфигурировать их адреса каждый раз, когда приезжаете на новое место, потому что в нём используется другая подсеть.

Решить эту проблему очень просто! Достаточно добавить в стойку небольшой маршрутизатор, чтобы у вас была постоянная подсеть, а NAT изолирует вас от изменения IP-адресов снаружи вашей маленькой сети. Ваша стойка имеет адреса 10.0.0.0/24, потому что их легко запомнить, а маршрутизатор получает IP-адрес на месте при помощи DHCP.

Всё это замечательно работает, пока не оказывается, что публичная сеть на месте проведения мероприятия тоже находится в сети 10.0.0.0/24. У маршрутизатора внезапно появляется одна и та же подсеть на обоих интерфейсах, а адреса в стойке начинают конфликтовать с другим оборудованием.

На этом этапе часто начинают выбирать для портативного оборудования странные подсети. «Каковы шансы, что на месте будет использоваться подсеть 172.16.42.0/24 или 10.11.12.0/24?» И да, это будет работать, но однажды у вас возникнет конфликт, потому что люди попросту не очень хорошо справляются с выбором случайных чисел. На самом деле, необязательно, чтобы сеть зависела от случайности, вам просто нужны другие возможности маршрутизаторов, нечасто применяемые в стандартных потребительских моделях.

Решение с IPv6

Наиболее официальное решение — это, разумеется, IPv6. Если внутри вашей приватной сети используется IPv6, то можно просто адресовать каждое устройство по его локальному адресу канала. Так как маршрутизатор разделяет сегмент сети между стойкой и публичной сетью, вы будете знать, что все локальные адреса каналов всегда будут вашими собственными устройствами.

Вам даже больше не понадобится DHCP-сервер в локальной сети. Каждое IPv6-устройство просто получает собственный адрес fe80::, а вы будете использовать протоколы сетевого обнаружения для нахождения адреса устройства. Например, для ресолвинга имён для этих адресов можно применять avahi.

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

Огромная проблема такого решения заключается в том, что поддержка IPv6 в устройствах, отличающихся от обычных компьютеров общего назначения, практически отсутствует. Прямо сейчас под рукой у меня есть портативная стойка с аудиомикшером Behringer X-Air, но он позволяет лишь использовать DHCP для получения адреса, никакой поддержки IPv6 в нём нет. Если взять произвольный видеомикшер, то, скорее всего, он не будет поддерживать IPv6, а в некоторых даже и DHCP ещё нет.

Строго говоря, такое же решение можно реализовать и в сети IPv4. Вероятно, вы с ним уже сталкивались: получали адрес 169.254.0.0/16 на компьютере при выборе DHCP, когда в сети нет работающего DHCP-сервера. Это адрес APIPA, в IPv4 эквивалентный адресу IPv6 fe80::. К сожалению, в данной ситуации такое решение не очень подходит, потому что при работе с сетью APIPA никак не создать шлюз, так что доступа к Интернету у вас не будет. Кроме того, если ваша машина получает валидный IP-адрес для подключения к Интернету, то адрес APIPA обычно сбрасывается на этом интерфейсе, потому что больше не требуется. Как и в случае с поддержкой IPv6 во встроенном оборудовании, чаще всего он не реализуется.

Здесь можно использовать следующий трюк, если вы имеете с сетью IPv6 и ищете адреса хостов в вашем сегменте:

$ ping -c 2 -I enp3s0 ff02::1
... здесь ответы от различных устройств ...
$ ip -6 neigh show dev enp3s0
fe80::cc55:13ff:fe9b:82a2 lladdr ce:55:13:9b:82:a2 REACHABLE 
fe80::df8c:9c93:6850:7132 lladdr b0:35:9f:5a:b2:49 REACHABLE 
fe80::ac2b:55ff:fe62:a34 lladdr ae:2b:55:63:0a:34 REACHABLE 
fe80::a0b8:78ff:fe5c:8229 lladdr a2:b8:78:5a:82:29 REACHABLE 
fe80::5660:9ff:fee1:cb4b lladdr 54:60:09:e1:cb:4b REACHABLE 
fe80::f61e:57ff:fe61:9a58 lladdr f4:1e:57:91:9a:58 router REACHABLE

Так можно отправить локальному сегменту широковещательный пинг, а потом считать список соседей, известных на этом интерфейсе, что также позволит вам узнать, какое из устройств рассылает уведомления о маршрутах. ff02::1 — это один из «примечательных групповых адресов ipv6», удобный список которых есть в Википедии.

Более общее решение

Вместо того, чтобы использовать более экзотическую адресацию внутри встроенной сети, можно выбрать решение, ограничивающее все странности одним лишь маршрутизатором. Можно сконфигурировать маршрутизатор так, чтобы обе сети, к которым он подключается, имели одну и ту же подсетку благодаря наличию отдельных таблиц маршрутизации для интерфейсов.

Это значит, что ваша внутренняя сеть может иметь вид 10.0.0.0/24 и внешняя сеть (на месте проведения мероприятия) тоже может быть 10.0.0.0/24, и всё без проблем будет работать. Видеомикшер в стойке может иметь адрес 10.0.0.4 и в внешней сети может быть адрес 10.0.0.4, но при этом ничто не будет конфликтовать. Разумеется, при таком решении придётся идти на компромисс; в данном случае он заключается в том, что вы больше не сможете дотягиваться до устройств в внешней сети, но это не должно стать проблемой, если вы подключаетесь к ней только для доступа к Интернету.

Волшебным решением здесь могут быть VRF. Обычно у маршрутизатора есть только одна таблица маршрутизации, определяющая, куда должен двигаться трафик на основании адреса получателя. Таблица маршрутизации — основная проблема в данной ситуации, потому что при наличии одинаковых подсетей внутри и снаружи в таблице просто будет два маршрута, сообщающих, что 10.0.0.0/24 должен относиться к интерфейсу LAN и к интерфейсу WAN.

$ ip route
default via 10.0.0.1 dev enp1s0 proto dhcp src 10.0.0.33 metric 100
10.0.0.0/24 dev enp1s0 proto kernel scope link src 10.0.0.33 metric 100
10.0.0.0/24 dev enp2s0 proto kernel scope link src 10.0.0.254 metric 100

По сути, мы сообщаем маршрутизатору, что одна и та же сеть 10.0.0.0/24 достижима по обоим интерфейсам. Единственный способ сообщить ядру, что на самом деле они отдельные — использование VRF.

Благодаря VRF у вас будет полностью изолированная таблица маршрутизации, которую можно привязать к сетевым интерфейсам. Для принятия решений о маршрутизации трафик от этих интерфейсов теперь сопоставляется с данной таблицей, а не с основной.

В моей тестовой системе я использовал устройство Mikrotik, потому что оно позволило мне конфигурировать VRF, так как у меня не было Linux-устройства с достаточным количеством интерфейсов для создания простого теста. Но в то же время это показывает, что подобная система не настолько эзотерична, что для её маршрутизации понадобился бы полнофункциональный PC. Я выбрал Mikrotik hAP mini, это трёхпортовый маршрутизатор за $15 — вероятно, самое дешёвое из устройств с этой функцией. Для тестирования у меня есть порт WAN (ether1) подключённый к моей домашней сети, а два других порта подключены к ноутбукам, которые должны общаться друг между другом, но оставаться изолированными от домашней сети.

Базовая конфигурация, уже настроенная в этом устройстве, позволяет ему обеспечивать NAT между двумя портами LAN и портом WAN, поэтому единственное, что мне оставалось сделать — разбить их, сделав внутреннюю подсеть такой же, что и у моей домашней сети, а затем сконфигурировать всё, что связано с VRF, для правильной маршрутизации.

# У bridge-internal есть два порта для внутренних устройств
/interface bridge
add name=bridge-internal
/interface bridge port
add bridge=bridge-internal interface=ether2
add bridge=bridge-internal interface=ether3

# Даём маршрутизатору адрес во внутренней сети
/ip address
add address=10.0.0.1/24 interface=bridge-internal

# Получаем адрес для интерфейса WAN от DHCP
/ip dhcp-client
add interface=ether1

# Создаём vrf стойки для bridge
/ip vrf
add interfaces=bridge-internal name=rack

# VRF в стойке сообщает ей, что шлюз по умолчанию находится в основной VRF
# по адресу 10.0.0.254. IP шлюза _может_ быть тоже может быть адресом 10.0.0.1, 
# который я использовал для этого маршрутизатора, но в данном случае я сделал их разными,
# чтобы конфигурация была понятнее
/ip route
add gateway=10.0.0.254@main routing-table=rack

# Правило iptables для обычного использования NAT для всего трафика, исходящего через порт WAN
/ip firewall nat
add action=masquerade chain=srcnat out-interface=ether1

# Используем отслеживание соединения, чтобы помечать трафик от внутренней VRF с целью доставки
# обратного трафика на ту же VRF. Первое правило даёт соединению
# пометку "rack" в таблице отслеживания соединений. Второе правило
# сопоставляет трафик с порта WAN, соответствующего соединению, имеющему
# пометку "rack", а затем настраивает таблицу маршрутизации для использования "rack", то есть
# VRF. Это цепочка предварительной маршрутизации, поэтому эти правила исполняются
# до того, как производятся действия с таблицами маршрутизации.
/ip firewall mangle
add action=mark-connection chain=prerouting connection-state=new in-interface=bridge-internal new-connection-mark=rack
add action=mark-routing chain=prerouting connection-mark=rack in-interface=ether1 new-routing-mark=rack

Вот и всё, что нужно. Трафик, обрабатываемый VRF стойки, доставляется на интерфейсы, связанные с этой VRF. Трафик для основной таблицы маршрутизации выходит из порта WAN.

Чтобы предназначенный для Интернета трафик пересекал границу между таблицами маршрутизации, в VRF добавляется маршрут, отправляющий предназначенный для Интернета трафик на адрес шлюза по умолчанию в основной таблице маршрутизации. Она пропускает его через правила файрволла и применяет стандартное правило NAT, заменяющее адрес отправителя на адрес маршрутизатора. Также в трекер соединений добавляется пометка соединения, сообщающая iptables, что источником этого соединения была VRF стойки.

Когда пакет возвращается из Интернета, трекер соединений iptables сопоставляет его с соединением, у которого есть пометка соединения. При этом срабатывает ещё одно mangle-правило, гарантирующее, что этот пакет обрабатывается VRF стойки, чтобы он был отправлен обратно на устройств в стойке, создавшее это соединение.

Всё это позволяет устройствам в стойке иметь подключение к Интернету, как будто это обычное подключение с NAT. Однако через него невозможно получить доступ к другим устройствам в моей домашней сети, потому что таблица маршрутизации для стойки просто будет отправлять предназначенный для 10.0.0.0/24 обратно по тому же интерфейсу, а не через порт WAN. То же самое происходит, когда устройство в домашней сети пытается использовать маршрутизатор в качестве шлюза для доступа к устройству в стойке.

Эти немногочисленные правила, сконфигурированные в маршрутизаторе, позволят вам использовать внутри стойки любимую подсеть, не беспокоясь о конфликтах. Я видел, как в такой ситуации применялись обычные сети с NAT для портативного оборудования прямых трансляций и для оборудования промышленного мониторинга, а однажды настраивал подобное для древнего станка с ЧПУ, не позволявшего менять адрес подсети.

При добавлении нескольких трансляций это также должно быть применимо для команд VRF в маршрутизаторах с Linux; к тому же, я предполагаю, что VRF также есть в маршрутизаторах других популярных марок.

Комментарии (2)


  1. net_racoon
    03.09.2025 08:41

    ИМХО проблема высосана из пальца. Во-первых, можно подобрать реально случайный диапазон, благо в 10ой сети их много. Во-вторых, для внутренней подсети можно взять какие-нибудь зарезервированные адреса. В-третьих, можно использовать DHCP для внутренней подсети и менять адресацию одной командой.


    1. BDI
      03.09.2025 08:41

      можно использовать DHCP для внутренней подсети и менять адресацию одной командой

      Ожидал такого решения походу чтения этой статьи(самое простое - заготовить два диапазона, и если первый используется на внешней сети, то отключать его), пока не наткнулся на упоминание устройств умеющих только статический IP4. В этом случае смена выдаваемых DHCP адресов проблему полностью не решает.