У меня есть небольшая сеть с маршрутизатором, который поддерживает подключение к Интернету, серверу и некоторым рабочим станциям в локальной сети.
Сервер предназначен для доступа из Интернета, и есть несколько записей DNAT, установленных в iptables маршрутизатора, например:
-A PREROUTING -i ppp0 -p tcp -m multiport --dports 22,25,80,443 -j DNAT --to-destination 192.168.2.10
Внешние пакеты приходят в роутер через ppp0
интерфейс, а внутренние идут от br-lan
, который фактически включает в себя коммутатор и адаптер WLAN. Проблема в том, что хотя внешний доступ работает нормально, попытка доступа к серверу изнутри локальной сети осуществляется с помощью внешнего IP-адреса, разрешенного DNS (назначенного для ppp0
) не работает.
Единственное решение, которое мне удалось придумать, - это добавить статические записи в маршрутизатор. /etc/hosts
указывающий на внутренний IP-адрес, но поскольку нет никаких подстановочных знаков (и у меня есть по крайней мере три домена верхнего уровня, назначенных этой системе, не считая десятков поддоменов), это довольно сложно и подвержено сбоям. Вы можете предложить что-нибудь получше?
Я только нашел это вопрос, что не очень помогло.
Если это уместно, маршрутизатор запускает OpenWRT 10.03 Kamikaze с dnsmasq.
Я удалил свой исходный ответ, потому что не был полностью уверен в его правильности. С тех пор у меня было время настроить небольшую виртуальную сеть виртуальных машин для имитации рассматриваемой сети. Вот набор правил брандмауэра, которые у меня сработали (в iptables-save
формат, для nat
только таблица):
-A PREROUTING -d 89.179.245.232/32 -p tcp -m multiport --dports 22,25,80,443 -j DNAT --to-destination 192.168.2.10
-A POSTROUTING -s 192.168.2.0/24 -o ppp0 -j MASQUERADE
-A POSTROUTING -s 192.168.2.0/24 -d 192.168.2.10/32 -p tcp -m multiport --dports 22,25,80,443 -j MASQUERADE
Первый POSTROUTING
rule - это простой способ совместного использования интернет-соединения с локальной сетью. Я оставил это здесь для полноты картины.
В PREROUTING
Правило и второе POSTROUTING
rule вместе устанавливают соответствующие NAT, так что соединения с сервером через внешний IP-адрес могут происходить независимо от того, исходят ли соединения извне или изнутри LAN. Когда клиенты в локальной сети подключаются к серверу через внешний IP-адрес, сервер видит, что соединения поступают с внутреннего IP-адреса маршрутизатора (192.168.2.1).
Интересно, что есть несколько вариантов второго правила POSTROUTING, которые также работают. Если цель изменена на -j SNAT --to-source 192.168.2.1
, эффект (что неудивительно) такой же, как у MASQUERADE
: сервер видит подключения от клиентов локальной сети как исходящие от маршрутизатора внутренний Айпи адрес. С другой стороны, если цель изменена на -j SNAT --to-source 89.179.245.232
, то NAT по-прежнему работает, но на этот раз сервер видит подключения от клиентов локальной LAN как исходящие от маршрутизатора внешний IP-адрес (89.179.245.232).
Наконец, обратите внимание, что ваш исходный PREROUTING
/DNAT
править с -i ppp0
не работает, потому что правило никогда не сопоставляет пакеты, приходящие от клиентов LAN (поскольку они не попадают в маршрутизатор через ppp0
интерфейс). Можно было бы заставить его работать, добавив второй PREROUTING
правило только для клиентов внутренней локальной сети, но оно было бы неэлегантным (IMO) и все равно должно было бы явно ссылаться на внешний IP-адрес.
Теперь, даже после того, как я подробно изложил решение «шпильки NAT» (или «обратной петли NAT», или «отражения NAT», или как бы то ни было), я по-прежнему считаю, что решение DNS с разделенным горизонтом - -с внешними клиентами, разрешающимися на внешний IP-адрес, и внутренними клиентами, разрешающимися на внутренний IP-адрес --- было бы более целесообразным путем. Зачем? Потому что больше людей понимают, как работает DNS, чем понимают, как работает NAT, и большая часть построения хороших систем заключается в использовании частей, которые можно обслуживать. Настройка DNS с большей вероятностью будет понята и, следовательно, правильно поддержана, чем таинственная настройка NAT (IMO, конечно).
Я удивлен, что спустя почти 8 лет никто так и не объяснил, как это сделать правильно, используя систему конфигурации UCI, используемую по умолчанию в OpenWRT.
Ответ Стивена Понедельника правильный, но он использует iptables
напрямую, что является более низким уровнем, чем система конфигурации UCI, и по возможности его лучше не трогать большинству пользователей OpenWRT.
Правильный способ доступа к внутренним серверам через их общедоступные комбинации IP / портов с другого внутреннего хоста в UCI - это включить параметр конфигурации reflection
под каждой конкретной целью DNAT в файле /etc/config/firewall
. Это поведение задокументировано Вот.
Например:
config redirect
option target 'DNAT'
option src 'wan'
option dest 'lan'
option proto 'tcp'
option src_dport '44322'
option dest_ip '192.168.5.22'
option dest_port '443'
option name 'apache HTTPS server'
option reflection '1'
Примечание. Согласно указанной документации OpenWRT, reflection
по умолчанию включен. В моем тестировании этого не произошло.
Распространенным решением является направление ваших внутренних хостов на локальный DNS-сервер, который возвращает правильный «внутренний» адрес для этих имен хостов.
Другое решение - и мы используем его там, где я работаю над нашими брандмауэрами Cisco - это переписать ответы DNS на брандмауэре, соответствующие этим адресам. Я не думаю, что есть инструменты для Linux, которые делают это прямо сейчас.
Вы должны иметь возможность настроить маршрутизацию на своем шлюзе, чтобы поступать правильно. Возможно, вам потребуется настроить серверы, чтобы они знали свой внешний IP-адрес (например, назначив его фиктивному интерфейсу). При такой конфигурации связь от одной внутренней системы к другой внутренней системе - с использованием ее «внешнего» адреса - будет проходить через маршрутизатор.
То, что вы просите сделать, называется NAT Loopback
и для этого требуется, чтобы вы добавили правило SNAT, чтобы пакеты, исходящие из вашей локальной сети на ваш сервер, возвращались через маршрутизатор:
-A POSTROUTING -p tcp -s 192.168.2.0/24 -d 192.168.2.10 -m multiport --dports 22,25,80,443 -j SNAT --to-source 89.179.245.232
Комментарий larsks о размещении внутренней версии пространства имен \ домена - это, как правило, способ решения этой проблемы в прошлом. Конечно, для этого вам понадобится внутренний DNS-сервер.
Я придумал следующее решение, позволяющее моей гостевой сети подключаться к портам, которые были перенаправлены из моей глобальной сети в локальную. Этот сценарий находится в моем разделе «Сеть -> Брандмауэр -> Пользовательские правила»:
# lookup the public IP (DDNS resolves to this)
wanip=$(ip route get 8.8.8.8 | awk -F"src " 'NR==1{split($2,a," ");print a[1]}')
# Guest network to LAN
# srcname is the guest network name, this needs to match for iptables
srcname=guest
# CIDR notation of guest and lan networks
srcnet=192.168.15.0/24
tgtnet=192.168.10.0/24
# router (openwrt) IP on lan network
tgtrouter=192.168.10.1
# host on lan network where ports are normally forwarded
tgthost=192.168.10.5
# ports to forward as a list or range
tcpports=8080,9090
udpports=12345
prechain=prerouting_${srcname}_rule
postchain=postrouting_${srcname}_rule
# reset the tables to prevent duplicate rules
iptables -t nat -F ${prechain}
iptables -t nat -F ${postchain}
iptables -t nat -A ${prechain} -s ${srcnet} -d ${wanip}/32 -p tcp -m tcp -m multiport --dports ${tcpports} -m comment --comment "${srcname} NAT reflection TCP DNAT" -j DNAT --to-destination ${tgthost}
iptables -t nat -A ${postchain} -s ${srcnet} -d ${tgthost}/32 -p tcp -m tcp -m multiport --dports ${tcpports} -m comment --comment "${srcname} NAT reflection TCP SNAT" -j SNAT --to-source ${tgtrouter}
iptables -t nat -A ${prechain} -s ${srcnet} -d ${wanip}/32 -p udp -m udp -m multiport --dports ${udpports} -m comment --comment "${srcname} NAT reflection UDP DNAT" -j DNAT --to-destination ${tgthost}
iptables -t nat -A ${postchain} -s ${srcnet} -d ${tgthost}/32 -p udp -m udp -m multiport --dports ${udpports} -m comment --comment "${srcname} NAT reflection UDP SNAT" -j SNAT --to-source ${tgtrouter}
Чтобы поддерживать перезагрузку, мне нужно было запустить следующее из командной строки ssh на openwrt (в противном случае, я считаю, что существует состояние гонки, когда некоторые правила были добавлены, а затем сброшены во время перезагрузки):
uci set firewall.@include[0].reload="1"
uci commit firewall
Отражение NAT настраивается для соединений в сети LAN с самим собой, но не с другими сетями, если вы создали несколько интерфейсов для изоляции трафика. Я попытался настроить правило переадресации из веб-интерфейса, но он отправляет весь трафик на порт из гостевой сети на этот узел локальной сети. Вышеупомянутый перехватывает только запросы к WAN IP, а не весь сетевой трафик.
Вместо этого можно использовать внутренний DNS, но только если все переадресации портов идут только на один хост. Если у вас есть несколько хостов, на которые вы перенаправляете разные порты, вы можете повторить правила для разных портов на разные tgthost
IP-адреса и порты.
Для всех, кто хочет сделать это с помощью nftables (официальная замена iptables), вот что я придумал:
define dnat_targets = {
http : 10.0.10.1 . http,
https : 10.0.10.1 . https,
32400 : 10.0.10.4 . 32400,
25565 : 10.0.10.8 . 25565,
}
define dnat_allowed = {
10.0.10.1 . http,
10.0.10.1 . https,
10.0.10.4 . 32400,
}
table inet nat {
map dnat_destinations {
type inet_service : ipv4_addr . inet_service
elements = $dnat_targets
}
set dnat_masq {
type ipv4_addr . inet_service
elements = $dnat_allowed
}
chain prerouting {
ip daddr != 10.0.0.0/8 fib daddr type local dnat ip addr . port to tcp dport map @dnat_destinations
}
chain postrouting {
ip saddr 10.0.0.0/8 ip daddr . tcp dport @dnat_masq masquerade
}
}
table inet filter {
set dnat_allowed {
type ipv4_addr . inet_service
elements = $dnat_allowed
}
chain forward {
ip daddr . tcp dport @dnat_allowed accept
}
}
Обратите внимание, что это фрагмент из моего определения брандмауэра, вам необходимо создать цепочки перед его использованием. Это также не совсем соответствует исходной ситуации с отправкой, необходимо адаптировать IP-адрес и диапазоны RFC1918.
Чтобы добавить цели DNAT, вам нужно только добавить их в dnat_targets
определение, а затем разрешите пункт назначения в dnat_allowed
устанавливать. Насколько я могу судить, вы не можете сделать это только с dnat_targets
установлен, но одним из преимуществ этого способа является то, что вы можете включать и выключать правила dnat, удаляя их из dnat_allowed
установить, сохраняя при этом отображение на случай, если оно вам понадобится позже.
Что действительно приятно в этом, так это то, что карты являются конструкциями первого класса в nftables, другими словами, независимо от того, сколько у вас целей DNAT (1,10,100,1000), пакетам нужно только пройти эти три правила, которые используют карты и наборы (аналогично тому, как работает ipset).
Еще я добавил, чтобы это работало с использованием неизвестного общедоступного IP-адреса, поэтому вы можете безопасно использовать его, когда WAN-интерфейс использует DHCP, и вы все равно можете запускать веб-сайт, доступный по локальной сети, или что-то еще в этом отношении на маршрутизаторе. коробка.
Наконец, здесь не показано правило маскарада для WAN-соединения, которое должно быть полностью функциональным.
Прохождение правил по одному:
ip daddr != 10.0.0.0/8 fib daddr type local dnat ip addr . port to tcp dport map @dnat_destinations
Это основное правило DNAT, если адрес назначения не находится в 10.0.0.0/8 и это местный адрес (определяется как любой адрес, назначенный интерфейсу на локальном компьютере), то мы собираемся выполнить на нем DNAT. Это то, что гарантирует соответствие только пакетам, предназначенным для неизвестного адреса WAN. Обратите внимание: если вы пропустите daddr != 10.0.0.0/8
тогда правило dnat будет сопоставлять запрос с любым интерфейсом на маршрутизаторе, поэтому веб-интерфейс администратора будет отображаться вместо того, чтобы отображаться, например, при доступе через 10.0.0.1:80, и если вы пропустите fib daddr type local
тогда любой запрос на что-либо, использующий любой из портов на карте (например, любой веб-сайт), будет обработан (например, если вы попытаетесь перейти на google.com на одном из ваших клиентов, вы окажетесь на сайте, который пытаетесь вместо этого разместить).
У моего роутера несколько LAN-адресов, если у вас только один, вы можете еще больше упростить правило. DNAT определяется с помощью поиска на карте порта назначения.
ip saddr 10.0.0.0/8 ip daddr . tcp dport @dnat_masq masquerade
Это аналогично правилу маскарада в ответе iptables, если источником является LAN-адрес, а адрес назначения и порт находятся в dnat_allowed
установить, затем маскарад. Причина, по которой это заставляет его работать, кстати, заключается в том, что если вы не измените адрес источника, тогда, когда сервер отправится отвечать на веб-запрос, он увидит адрес локальной сети, а затем arp "у кого есть" эта локальная сеть адрес, ваша машина ответит на этот запрос arp, а затем напрямую отправит пакет на ваш локальный компьютер. Однако ваш локальный компьютер сделал запрос к общедоступному IP-адресу маршрутизатора, поэтому, когда он получает ответ от сервера напрямую, он не знает, что с ним делать, поскольку он не ожидал пакета с этого адреса, поэтому он отмечает его как недействительный и отбрасывает его. Маскируясь здесь, вы заставляете веб-сервер отвечать маршрутизатору, и маршрутизатор отправляет его обратно на вашу машину, используя conntrack.
ip daddr . tcp dport @dnat_allowed accept
Наконец, правило прямого фильтра, если адрес назначения и порт находятся в dnat_allowed
установите, затем примите пакет.