nft config, чтобы сделать локальный FTP-сервер NAT общедоступным

nft config, чтобы сделать локальный FTP-сервер NAT общедоступным

Все будет в изолированной сети, безопасность не проблема.
eth0 подключен к «публичной» сети. Адрес назначается DHCP.
eth1 подключен к серверу «частной сети», который предоставляет ssh, telnet, «другие» и ftp.
В этом примере этот сервер будет иметь фиксированный IP (192.168.1.2).

Шлюз работает под управлением Debian Buster и ядра Linux 4.19.94.

nft используется с NAT.
Это моя конфигурация «шлюза» nft на данный момент:

table ip my_nat {
    chain my_prerouting { type nat hook prerouting priority 0;
    tcp dport { 2222 } dnat to :22 # 2222 backdoor for ssh to the gateway
    tcp dport { 1-1023 } dnat to 192.168.1.2
  }
  chain my_postrouting {
    type nat hook postrouting priority 100;
    ip daddr 192.168.1.2  masquerade
  }
}

Что мне нужно добавить, чтобы FTP заработал?

решение1

TL;DR

# nft add ct helper ip my_nat ftp-incoming '{ type "ftp" protocol tcp; }'
# nft add chain ip my_nat my_helpers '{ type filter hook prerouting priority 10; }'
# nft add rule ip my_nat my_helpers iif eth0 ip daddr 192.168.1.2 tcp dport 21 ct helper set ftp-incoming
# modprobe nf_nat_ftp

более подробная информация ниже...

Вспомогательные модули протоколов для проблемных протоколов

FTP — старый протокол, не очень дружелюбный к брандмауэрам: команды на командном канале FTP (21/TCP) согласовывают эфемерный порт для использования следующей командой передачи. Из-за этого брандмауэр с отслеживанием состояния должен отслеживать эти команды и ответы, чтобы временно разрешить соответствующий порт, который будет использоваться.

В Linux это обеспечивается вспомогательными модулями, специфичными для протокола, которые являются плагинами дляconntrack, подсистема Netfilter, отслеживающая соединения для NAT и брандмауэра с отслеживанием состояния. С FTP, когда на порту команды FTP обнаружено согласование порта (в основном PORT, EPRT, PASV или EPSV) для следующей передачи, помощник добавляет кратковременную запись в специальныйconntrackтаблица (ожидание conntracktable), который будет ожидать следующего связанного и ожидаемого подключения к данным.

В моем ответе используется современная «безопасная» обработка, описанная вэтот блог оiptablesдля общих черт и вnftablesвикииman nftдля обработки вnftablesкоторый отличается отiptables.

Безопасное использование вспомогательных правил и правил nftables

Ядро Linux 4.7+ (включая 4.19) по умолчанию использует безопасный подход: загруженный вспомогательный модуль (в данном случае FTP) больше не позволит ему отслеживать все пакеты, имеющие исходный или целевой порт TCP 21, пока не будет указан определенныйnftables(илиiptables) операторы сообщают ему, в каком (ограниченном) случае он должен шпионить. Это позволяет избежать ненужного использования ЦП и позволяет в любое время изменить порт(ы) FTP для шпионажа, просто изменив несколько правил (или наборов).

Первая часть — объявить потоки, которые могут запустить слежку. Это обрабатывается по-разному вnftablesчем вiptables. Здесь он объявлен с использованием ct helperобъекта с сохранением состояния, и фильтры для его активации должны быть выполнены послеconntrack(покаiptablesтребует действий, выполненных ранее).man nftрассказывает:

В отличие от iptables, назначение помощника необходимо выполнять после завершения поиска conntrack, например, с приоритетом хука по умолчанию 0.

nft add ct helper ip my_nat ftp-incoming '{ type "ftp" protocol tcp; }'

nft add chain ip my_nat my_helpers '{ type filter hook prerouting priority 10; }'
nft add rule ip my_nat my_helpers iif eth0 ip daddr 192.168.1.2 tcp dport 21 ct helper set ftp-incoming

Я выбрал ту же таблицу, но ее можно было бы создать в другой таблице, если бы объявление объекта с сохранением состояния и правило, ссылающееся на него, находились в той же таблице.

Конечно, можно выбрать менее строгие правила. Замена последнего правила следующим правилом будет иметь тот же эффект, что и режим legacy:

nft add rule ip my_nat my_helpers tcp dport 21 ct helper set ftp-incoming

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

sysctl -w net.netfilter.nf_conntrack_helper=1

Обеспечение nf_nat_ftpзагрузки

Модуль ядра nf_conntrack_ftpавтоматически загружается с зависимостью, созданной ct helper ... type "ftp". Это не относится к nf_nat_ftp, но он также необходим для включения искажения пакетов в командном порту, когда NAT выполняется на портах потока данных.

Например, чтобы модуль nf_nat_ftpизвлекался всякий раз, когда nf_conntrack_ftpзагружается, /etc/modprobe.d/local-nat-ftp.confможно добавить файл со следующим содержимым:

install nf_conntrack_ftp /sbin/modprobe --ignore-install nf_conntrack_ftp; /sbin/modprobe --ignore-install nf_nat_ftp

или вместо этого просто добавьте, например, /etc/modules-load.d/local-nat-ftp.confследующее:

nf_nat_ftp

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

modprobe nf_nat_ftp

О брандмауэре

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

Например, хотя вспомогательный модуль FTP обрабатывает как пассивный, так и активный режимы, если по какой-то причине требуется разрешить только пассивный режим (с передачей данных от клиента к серверу) и не разрешать «активный» FTP (передача данных от исходного порта сервера 20 к клиенту), можно использовать, например, следующие правила в части брандмауэра набора правил вместо обычных ct state established,related accept:

ct state established accept
ct state related ct helper "ftp" iif eth0 oif eth1 tcp sport 1024-65535 accept
ct state related ct helper "ftp" drop
ct state related accept 

Другой видсвязанныйпотоки, не связанные с FTP, принимаются (или могут быть дополнительно разделены отдельно)


Пример обращения с помощником

Здесь (в смоделированной среде) находятся дваconntrackсписки событий, измеренных наожиданиестол иconntrackтаблица с правилами OP + дополнительные правила выше с интернет-клиентом 203.0.113.101, выполняющим FTP в пассивном режиме с публичным IP-адресом маршрутизатора 192.0.2.2 и использующим команду LIST после входа в систему:

# conntrack -E expect
    [NEW] 300 proto=6 src=203.0.113.101 dst=192.0.2.2 sport=0 dport=37157 mask-src=0.0.0.0 mask-dst=0.0.0.0 sport=0 dport=65535 master-src=203.0.113.101 master-dst=192.0.2.2 sport=50774 dport=21 class=0 helper=ftp
[DESTROY] 300 proto=6 src=203.0.113.101 dst=192.0.2.2 sport=0 dport=37157 mask-src=0.0.0.0 mask-dst=0.0.0.0 sport=0 dport=65535 master-src=203.0.113.101 master-dst=192.0.2.2 sport=50774 dport=21 class=0 helper=ftp

одновременно:

# conntrack -E
    [NEW] tcp      6 120 SYN_SENT src=203.0.113.101 dst=192.0.2.2 sport=50774 dport=21 [UNREPLIED] src=192.168.1.2 dst=192.168.1.1 sport=21 dport=50774 helper=ftp
 [UPDATE] tcp      6 60 SYN_RECV src=203.0.113.101 dst=192.0.2.2 sport=50774 dport=21 src=192.168.1.2 dst=192.168.1.1 sport=21 dport=50774 helper=ftp
 [UPDATE] tcp      6 432000 ESTABLISHED src=203.0.113.101 dst=192.0.2.2 sport=50774 dport=21 src=192.168.1.2 dst=192.168.1.1 sport=21 dport=50774 [ASSURED] helper=ftp
    [NEW] tcp      6 120 SYN_SENT src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 [UNREPLIED] src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835
 [UPDATE] tcp      6 60 SYN_RECV src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835
 [UPDATE] tcp      6 432000 ESTABLISHED src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835 [ASSURED]
 [UPDATE] tcp      6 120 FIN_WAIT src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835 [ASSURED]
 [UPDATE] tcp      6 30 LAST_ACK src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835 [ASSURED]
 [UPDATE] tcp      6 120 TIME_WAIT src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835 [ASSURED]

Начало ожидания proto=6 src=203.0.113.101 dst=192.0.2.2 sport=0 dport=37157говорит о том, что следующее TCP-соединение с 203.0.113.101:* на 192.0.2.2:37157 будет связано (состояниесвязанный) с FTP-подключением. Не видно напрямую, но поскольку также загружен вспомогательный модуль NAT FTP, фактические данные, отправленные сервером в ответ на команду PASV/EPSV, были перехвачены и преобразованы, поэтому клиент подключается к 192.0.2.2 вместо 192.168.1.2, что, конечно, привело бы к сбою на клиенте.

Несмотря на второй поток (второйНОВЫЙлиния) не имеющая явного правила вmy_prerouting, он был успешно ДНК-кодирован на сервер за маршрутизатором.


Примечания

  • если порт управления FTP зашифрован ( AUTH TLS...), то вспомогательный модуль больше не может отслеживать согласованный порт, и это не может работать. Приходится прибегать к настройке зарезервированного диапазона портов как в конфигурации FTP-сервера, так и в брандмауэре/маршрутизаторе NAT, и настраивать сервер так, чтобы он отправлял правильный (публичный) IP-адрес при согласовании вместо своего собственного. И активный режим FTP не может использоваться, если у сервера нет маршрута в Интернет (как, по-видимому, и происходит в данном случае).

  • придирки: приоритет предварительной маршрутизации 10 гарантирует, что даже для ядер < 4.18, NAT уже произошел для новых потоков (OP выбрал приоритет предварительной маршрутизации hook 0 вместо обычного -100, поскольку это редко имеет значение в nftables), поэтому использование daddr 192.168.1.2возможно. Если приоритет был 0 (или ниже 0), то, возможно (не проверено), правило увидит первый пакет все еще не подвергнутым NAT с публичным IP-адресом назначения, но перехватит следующие пакеты того же потока, поскольку они обрабатываются напрямуюconntrackс приоритетом -200. Лучше перестраховаться и использовать 10. На самом деле это не актуально с ядра 4.18 (см.совершитьссылка вэтотожидающий исправления), где приоритет NAT имеет значение только для сравнения между несколькими цепочками NAT (и позволяет смешивать NAT в iptables legacy с nftables).

решение2

После некоторых проб и ошибок я пришел к следующему nftables.conf. Он работает так, как и предполагалось, и поддерживает NAT в обоих направлениях, а также экспортирует все порты моего сервера, кроме одного, в "публичную" сеть. Порт 2222 по-прежнему используется как "черный ход" к шлюзу, который можно использовать, если мне когда-нибудь снова понадобится к нему доступ :-)

table ip my_nat {
        ct helper ftp-incoming {
                type "ftp" protocol tcp
                l3proto ip
        }

        chain my_prerouting {
                type nat hook prerouting priority 0; policy accept;
                iifname "eth0" tcp dport { 2222 } dnat to :ssh
                iifname "eth0" tcp dport { 1-2221, 2223-65535 } dnat to 192.168.0.2
        }

        chain my_postrouting {
                type nat hook postrouting priority 100; policy accept;
                ip daddr 192.168.0.2 masquerade
                oifname "eth0" masquerade
        }

        chain my_helpers {
                type filter hook prerouting priority 10; policy accept;
                iif "eth0" ip daddr 192.168.0.2 tcp dport ftp ct helper set "ftp-incoming"
        }

}

Связанный контент