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

Aug 18 2020

Все будет в изолированной сети, безопасность не проблема.
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 A.B Aug 20 2020 at 19:17

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, когда согласование порта (в основном PORT, EPRT, PASV или EPSV) для следующей передачи было замечено в командном порту FTP, помощник добавляет кратковременную запись в специальную таблицу conntrack ( таблица ожидания conntrack ), которая будет дождитесь следующего связанного и ожидаемого подключения для передачи данных.

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

Безопасное использование правил helper и 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

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

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

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

О межсетевом экране

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

Например, хотя вспомогательный модуль FTP обрабатывает как пассивный, так и активный режимы, если по какой-то причине кто-то хочет разрешить только пассивный режим (с подключением данных от клиента к серверу), а не «активный» ftp (подключение данных от порта источника сервера 20 к client) можно использовать, например, эти правила в части набора правил брандмауэра вместо обычных 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.0.1. 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, который имел бы конечно провалился на клиенте.

Несмотря на то, что второй поток (вторая строка NEW ) не имеет явного правила в my_prerouting , он был успешно применен DNAT к серверу за маршрутизатором.


Примечания

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

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

GunnarHolm Sep 04 2020 at 11:56

После некоторых проб и ошибок я получил следующий файл 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"
        }

}