Linux iptables ssh port forwarding (марсианский отказ)

У меня есть шлюз Linux, выполняющий NAT для моей домашней сети. У меня есть еще одна сеть, в которую я бы хотел прозрачно пересылать пакеты, но только к / с определенных IP-портов (т. Е. Не VPN). Вот несколько примеров IP и портов для работы с:

Source Router Remote Gateway Remote Target 192.168.1.10 -> 192.168.1.1 -> 1.2.3.4 -> 192.168.50.50:5000 

Я хотел бы, чтобы исходная машина могла разговаривать с определенными портами на удаленной цели, как если бы она была напрямую маршрутизирована с Router. На маршрутизаторе eth0 – это частная сеть, а eth1 – интернет. Удаленный шлюз – еще одна машина Linux, в которую я могу войти, и она может напрямую перенаправляться в Remote Target.

Моя попытка простого решения – настроить перенаправление портов ssh на маршрутизаторе, например:

 ssh -L 5000:192.168.50.50:5000 1.2.3.4 

Это отлично работает для маршрутизатора, который теперь может подключаться локально к порту 5000. Так что «telnet localhost 5000» будет подключен к 192.168.50.50:5000, как и ожидалось.

Теперь я хочу перенаправить трафик из источника и воронки через уже установленный туннель ssh. Я попытался использовать правило NAT:

 iptables -t nat -D PREROUTING -i eth0 -p tcp -s 192.168.1.10 --dport 5000 -d 1.2.3.4 -j DNAT --to-destination 127.0.0.1:5000 

и поскольку маршрутизатор уже является моим NAT-шлюзом, у него уже есть необходимое правило поэтапного продления:

 -A POSTROUTING -s 192.168.1.0/24 -o eth1 -j MASQUERADE 

Большинство вопросов и ответов на этом сайте или в других местах, похоже, имеют дело с пересылкой портов сервера или шпилькой NAT, оба из которых я отлично работаю в другом месте, ни одно из которых не применяется к этой ситуации. Я, конечно, мог DMZ перенаправить удаленные целевые порты через Remote Gateway, но я не хочу, чтобы порты были доступны в Интернете, я хочу, чтобы они были доступны только через безопасный SSH-туннель.

Лучший ответ, который я могу найти, относится к марсианскому отказу пакетов в ядре Linux:

iptables, как перенаправить порт из loopback?

Я включил протоколирование марсиан и подтвердил, что ядро ​​отклоняет эти пакеты в качестве марсиан. Кроме того, что это не так: я точно знаю, для чего предназначены эти пакеты, откуда они и куда они идут (мой туннель ssh).

Представленное там решение «окольного пути» применимо к этому оригинальному вопросу, но не относится к моему делу.

Однако при написании / исследовании этого вопроса я работал над своей проблемой, используя привязку IP-адреса источника SSH:

 ssh -L 192.168.1.1:5000:192.168.50.50:5000 1.2.3.4 iptables -t nat -D PREROUTING -i eth0 -p tcp -s 192.168.1.10 --dport 5000 -d 1.2.3.4 -j DNAT --to-destination 192.168.1.1:5000 

Поскольку я не использую loopback, это касается марсианского отказа.

Я все еще задаю этот вопрос по двум причинам:

  1. В надежде, что кто-то, пытающийся сделать что-то подобное в будущем, может найти это в своих поисках, и это обходное решение может им помочь.
  2. Я по-прежнему предпочитаю, чтобы мой ssh-порт пересылал соединение, связанное только с loopback и способное направить их через iptables. Поскольку я точно знаю, что такое эти пакеты и куда они идут, не должно ли я каким-то образом обозначить их как таковые, чтобы марсианская фильтрация Linux не отвергала их? Все мои поиски по этой теме приводят к rp_filter, что совсем не помогло в моем тестировании. И даже если это действительно сработало, это не относится к конкретным пакетам, которые я пытаюсь разрешить.

пс. Первоначально опубликовано в serverfault , так как я нашел несколько связанных ответов при попытке решить эту проблему. Первоначально я предполагал, что serverfault – это все вещи Unix / Linux и не понимал, что существует отдельный Exchange, но, согласно этой мета-почте, этот обмен, пожалуй, лучше подходит для этого вопроса. Я заинтересован в том, чтобы внести свой вопрос и обходной путь в общий поиск, чтобы сохранить кого-то еще в течение нескольких часов поиска, который я сделал только для того, чтобы придумать тупики, а также, надеюсь, кто-то ответит на петлевую / марсианскую часть моего вопроса, который все еще остается открытым мне.

Проблема с выполнением DNAT до 127.0.0.1:5000 заключается в том, что когда удаленная сторона отвечает, эти пакеты возвращаются в механизм маршрутизации, как если бы они были локально инициированы (из 127.0.0.1), но у них есть внешний адрес назначения. SNAT / MASQUERADE, соответствующие внешнему интерфейсу, поймали бы их и переписали, но решения маршрутизации, которые должны быть сделаны для пакетов, чтобы прийти к этому интерфейсу, являются первыми, и они запрещают эти пакеты, которые являются фиктивными по умолчанию. Механизм маршрутизации не может гарантировать, что вы запомните это позже.

То, что вы должны сделать, это отказаться от любых внешних подключений к 192.168.1.1:5000 в iptables INPUT, кроме тех, которые идут от 192.168.1.10, используя ! аргумент перед спецификацией адреса источника -s . Если вы используете TCP-сброс в качестве механизма отклонения ( -j REJECT --reject-with tcp-reset , а не по умолчанию для ICMP-адресата недоступен), он будет во многом идентичным ситуации, когда ничто не слушает по этому адресу: комбинация портов что касается внешнего мира.

Я бы использовал openVPN для создания туннеля от Router до RemoteGateway.

Тогда я бы на Router добавил маршрут:

route add -host RemoteTarget gw RemoteGateway-VPNaddress

используйте простое правило iptables, в котором вы хотите ограничить, какие порты вы разрешаете Source.