FTP tryb pasywny nie działa: jak naprawić firewall
Logowanie FTP przebiega pomyślnie, ale lista katalogów zawiesza się? Dowiedz się, jak skonfigurować zakres portów pasywnych i reguły firewalla, aby odblokować transfer danych.
Dlaczego FTP loguje się, ale lista katalogów zawiesza się
Tryb pasywny FTP nie działa poprawnie za firewallem, ponieważ FTP wykorzystuje dwa połączenia TCP, a nie jedno. Połączenie z portem 21 obsługuje logowanie oraz komendy, więc nazwa użytkownika i hasło są akceptowane, a konfiguracja firewalla wydaje się poprawna. Pierwsze ls wymaga następnie drugiego połączenia na innym porcie. Żadna reguła w firewallu nie zezwala na to połączenie, więc klient oczekuje do momentu przekroczenia limitu czasu.
Rozwiązaniem jest zdefiniowanie stałego zakresu portów dla połączeń danych oraz dodanie reguły firewalla zezwalającej na ten zakres. Serwer działający za NAT (network address translation) wymaga dodatkowego ustawienia, aby anonsował właściwy adres IP. Mechanizmy śledzenia połączeń (connection tracking helpers) wykonywały tę pracę automatycznie. Obecnie już tego nie robią, a powód warto poznać przed skorzystaniem ze starych poradników.
Kanał sterujący i kanał danych
Protokół FTP (file transfer protocol) został zdefiniowany w RFC 959 i powstał przed wprowadzeniem mechanizmów NAT oraz stanowych zapór sieciowych. Sesja otwiera jedno połączenie sterujące na porcie TCP 21 i utrzymuje je przez cały czas trwania sesji. Polecenia przesyłane są w postaci czystego tekstu. Odpowiedzi wracają jako trzycyfrowy kod wraz z linią tekstu. To połączenie nigdy nie przenosi zawartości plików.
Każdy element danych wymaga osobnego połączenia TCP: jednego dla listy katalogów (LIST), jednego dla każdego pobierania (RETR) oraz jednego dla każdego wysyłania (STOR). Połączenie jest otwierane, używane jednorazowo i zamykane. Uwierzytelnianie odbywa się w całości w kanale sterującym, dlatego uszkodzona ścieżka danych zawsze objawia się w ten sam sposób: udanym logowaniem, po którym następuje zawieszenie. Jeśli klient wyświetla odpowiedź 230, a następnie zatrzymuje się na pobieraniu listy, problem dotyczy kanału danych, a nie poświadczeń.
Tryb aktywny: serwer nawiązuje połączenie z klientem
W trybie aktywnym klient wybiera port, nasłuchuje na nim i informuje serwer, gdzie ma się połączyć:
PORT 192,168,1,50,195,80Pierwsze cztery liczby to adres IP klienta. Ostatnie dwie to port, zakodowany jako dwa bajty: 195 * 256 + 80 = 50000. Następnie serwer otwiera połączenie danych z własnego portu 20 do portu 50000 na kliencie.
To połączenie jest przychodzące i nieoczekiwane z punktu widzenia klienta, dlatego firewall klienta je odrzuca. Jeśli klient znajduje się za domowym routerem, adres w poleceniu PORT jest adresem prywatnym, do którego serwer nie ma żadnego dostępu. Tryb aktywny jest przyczyną reputacji FTP jako protokołu, który nie działa.
Tryb pasywny: klient otwiera oba połączenia
Tryb pasywny odwraca kierunek połączenia danych. Klient wysyła PASV, a serwer odpowiada własnym adresem oraz portem:
227 Entering Passive Mode (203,0,113,10,195,80)Kodowanie jest identyczne, więc klient łączy się z 203.0.113.10 na porcie 50000. Klient otwiera teraz oba połączenia, dlatego tryb pasywny działa poprawnie za NAT-em po stronie klienta i dlatego każdy współczesny klient żąda go w pierwszej kolejności.
Problem został przeniesiony, a nie wyeliminowany. Niezamówione połączenie przychodzące trafia teraz na serwer, na wysoki port, który zmienia się przy każdym transferze. Skoro firewall należy do administratora serwera, problem staje się jego problemem.
EPSV (rozszerzony tryb pasywny, RFC 2428) opiera się na tej samej koncepcji, oferując czytelniejszą odpowiedź:
229 Entering Extended Passive Mode (|||50000|)Nie zawiera ona adresu. Klient ponownie wykorzystuje adres, który już posiada dla połączenia sterującego, co umożliwia działanie w sieci IPv6 i eliminuje całą klasę błędów związanych z NAT. Dokumentacja curl wskazuje, że curl zazwyczaj próbuje EPSV przed PASV. Port nadal jest wybierany w czasie wykonywania, więc EPSV nie zmienia niczego w regułach firewalla.
Dlaczego standardowa reguła firewalla nie pozwala na otwarcie kanału danych
Ponieważ numer portu nie istnieje w momencie tworzenia reguły. Serwer wybiera go dla każdego transferu indywidualnie. Przy ustawieniach domyślnych, dokumentacja vsftpd określa pasv_min_port oraz pasv_max_port jako 0, co oznacza „użyj dowolnego portu”, więc połączenie danych może nadejść na dowolnym porcie powyżej 1023. sudo ufw allow 21/tcp zezwala jedynie na kanał sterujący i nic więcej; jest to dokładnie ta konfiguracja, która umożliwia poprawne logowanie, ale powoduje błąd przy próbie wyświetlenia zawartości katalogu. Jeśli koncepcja usługi nasłuchującej na jednym stałym porcie jest niejasna, jak działają porty i gniazda nasłuchujące w systemie Linux stanowi odpowiednie wprowadzenie teoretyczne.
Firewall stanowy (stateful) śledzi połączenia, a jądro systemu może dopuścić nowe połączenie jako RELATED do już istniejącego. W przypadku FTP wymaga to mechanizmu, który odczyta strumień sterujący i wyodrębni numer portu z linii 227 lub PORT. Domyślnie żaden mechanizm tego nie wykonuje.
Dlaczego moduł śledzenia połączeń FTP nie jest już właściwym rozwiązaniem
Moduł jądra nf_conntrack_ftp jest wskazywany w starszych poradnikach. Odczytuje on niezaszyfrowany kanał sterujący, odnajduje ogłoszony port i rejestruje oczekiwanie, dzięki czemu połączenie danych jest akceptowane bez konieczności tworzenia reguły dla tego portu. Od czasu powstania tych poradników zmieniły się cztery kwestie.
Automatyczne przypisywanie pomocników jest wyłączone, a w bieżących wersjach jądra nie można go ponownie włączyć. Jądro wyłączyło tę funkcję domyślnie w 2016 roku. Commit Pablo Neiry Ayuso "netfilter: remove nf_conntrack_helper sysctl and modparam toggles" (sierpień 2022) całkowicie usunął ten przełącznik, stwierdzając, że "użytkownicy muszą teraz polegać na jawnej konfiguracji pomocnika conntrack poprzez zestaw reguł". Parametr sysctl nf_conntrack_helper występuje w Linux 5.19, a od wersji Linux 6.0 został usunięty; dokumentacja sysctl dla conntrack w jądrze już go nie wymienia. Samo załadowanie modułu nie przynosi żadnego efektu.
Można sprawdzić wersję posiadanego jądra. Należy wykonać sysctl net.netfilter.nf_conntrack_helper. Odpowiedź sysctl: cannot stat /proc/sys/net/netfilter/nf_conntrack_helper: No such file or directory oznacza, że jądro nie posiada już funkcji automatycznego przypisywania pomocników. Jeśli zwrócona zostanie liczba, oznacza to, że używane jest jądro starsze niż 6.0, przełącznik nadal istnieje, a jego domyślna wartość to 0.
Narzędzia zarządzania firewallem również wycofały to rozwiązanie. man ufw-framework w systemie Ubuntu 24.04 odnośnie linii IPT_MODULES w pliku /etc/default/ufw podaje: "Bezwarunkowe ładowanie modułów śledzenia połączeń (nf_conntrack_*) w ten sposób jest przestarzałe" i dodaje, że reguły pomocników "muszą być zarządzane poprzez PLIKI REGUŁ". Dokumentacja firewalld określa AutomaticHelpers w firewalld.conf jako "Przestarzałe. Ta opcja jest ignorowana i nie jest już używana." Dołączanie pomocnika wymaga obecnie ręcznego utworzenia jawnej reguły z celem CT, co jest bardziej pracochłonne niż poniższe rozwiązanie i przestaje działać w momencie włączenia TLS. iptables i nftables w systemie Ubuntu opisuje, gdzie faktycznie znajdują się te reguły.
TLS kończy dyskusję. Pomocnik działa poprzez odczyt kanału sterującego jako tekst. Zaszyfrowanie tego kanału sprawia, że pomocnik widzi tekst zaszyfrowany, więc nie jest w stanie odnaleźć portu. Nie ma na to poprawki i nie powinno jej być: urządzenie pośredniczące zdolne do odczytania kanału sterującego to urządzenie, które odczytało hasło użytkownika.
Deklaracja zakresu portów pasywnych na serwerze
Każdy serwer FTP umożliwia wybór portów pasywnych z określonego zakresu. Nazwy opcji różnią się w zależności od oprogramowania, dlatego należy sprawdzić dokumentację używanego serwera.
vsftpd, w pliku /etc/vsftpd.conf:
pasv_enable=YES
pasv_min_port=30000
pasv_max_port=30099pasv_enable domyślnie korzysta z YES. Obie opcje portów mają domyślną wartość 0, co oznacza zachowanie „użyj dowolnego portu” opisane powyżej. Zastosuj zmiany za pomocą sudo systemctl restart vsftpd, a następnie potwierdź poprawność działania usługi poleceniem systemctl status vsftpd. vsftpd odmawia uruchomienia w przypadku napotkania nieprawidłowej linii konfiguracji zamiast jej ignorowania. Jeśli restart zakończy się niepowodzeniem, sprawdź journalctl -u vsftpd -n 20 pod kątem linii 500 OOPS: zawierającej wpisaną opcję.
ProFTPD, w pliku proftpd.conf:
PassivePorts 30000 30099ProFTPD nie definiuje tutaj wartości domyślnej: bez tej dyrektywy port przydziela jądro systemu. Dokumentacja wskazuje, że gdy w zdefiniowanym zakresie nie ma wolnego portu, serwer korzysta z portu przydzielonego przez jądro i zapisuje komunikat w dzienniku. Zbyt mały zakres powoduje zatem sporadyczne błędy zamiast całkowitego zatrzymania usługi, co jest znacznie trudniejsze w diagnostyce. Należy używać portów nieuprzywilejowanych, czyli 1024 i wyższych.
Pure-FTPd przyjmuje flagę -p first:last, opisaną w man pure-ftpd jako „Używaj tylko portów z zakresu od pierwszego do ostatniego włącznie dla pobierania w trybie pasywnym”, co „zwiększa kompatybilność pure-ftpd z filtrami pakietów”. Pakiety dystrybucyjne zazwyczaj umieszczają tę flagę w pliku konfiguracyjnym, dlatego zamiast zgadywać, należy sprawdzić dokumentację danej dystrybucji w celu ustalenia nazwy pliku.
Ile portów jest potrzebnych? Jeden na każde aktywne połączenie danych. Zamknięty port TCP pozostaje w stanie TIME_WAIT przez kilka minut, zanim będzie mógł zostać ponownie użyty, dlatego należy przewidzieć zapas wielokrotnie przekraczający oczekiwane szczytowe obciążenie. Zakres stu portów jest wystarczający dla kilku użytkowników, natomiast obciążony serwer publiczny wymaga znacznie większej liczby. vsftpd jest w tej kwestii mniej wyrozumiały niż ProFTPD: kod źródłowy próbuje losować kilka portów z zakresu, a jeśli wszystkie są zajęte, kończy sesję błędem 500 OOPS: vsf_sysutil_bind zamiast wypożyczyć port spoza zakresu. Na obu serwerach zbyt mały zakres spowoduje przerwanie transferów w najbardziej obciążonym momencie.
Gdzie powinien znajdować się zakres? Najpierw wykonaj sysctl net.ipv4.ip_local_port_range. W standardowej instalacji Ubuntu wynik to 32768 60999, czyli porty przydzielane przez jądro dla połączeń wychodzących. Zakres pasywny wewnątrz tego okna może kolidować z połączeniem wychodzącym, które już zajmuje dany port, dlatego zakres należy utrzymać poniżej tej wartości. Zakres od 30000 do 30099 jest bezpieczny w domyślnej konfiguracji. Należy jednak sprawdzić własny system, zamiast polegać na tej wartości.
Otwarcie tego samego zakresu w zaporze sieciowej
Narzędzie ufw zapisuje zakresy przy użyciu dwukropka, a dokumentacja wskazuje, że zakres lub lista „mogą być również użyte do określenia wielu portów, w takim przypadku wymagane jest podanie protokołu”:
sudo ufw allow 21/tcp
sudo ufw allow 30000:30099/tcp
sudo ufw status verboseufw status verbose powinno teraz wyświetlić oba wpisy. To samo polecenie bez /tcp zostanie odrzucone z błędem informującym o konieczności wskazania tcp lub udp, ponieważ ufw nie podejmuje prób zgadywania. składnia reguł ufw na VPS omawia pozostałe kwestie.
Narzędzie firewalld zapisuje zakres przy użyciu myślnika i wymaga przeładowania:
sudo firewall-cmd --permanent --add-service=ftp
sudo firewall-cmd --permanent --add-port=30000-30099/tcp
sudo firewall-cmd --reload
sudo firewall-cmd --list-all--add-service=ftp otwiera port 21/tcp i żąda użycia pomocnika ftp, co jest zdefiniowane w dostarczonej definicji usługi. Nie otwiera to jednak pasywnego zakresu portów, więc samodzielnie nie rozwiązuje problemu. strefy i usługi firewalld na VPS przedstawia szerszy kontekst.
Bezpośrednie użycie nftables wewnątrz łańcucha wejściowego (input chain):
tcp dport { 21, 30000-30099 } acceptNależy pamiętać o jeszcze jednej zaporze: większość dostawców utrzymuje sieciową zaporę w panelu sterowania, poza systemem operacyjnym. Jeśli reguły na serwerze są poprawne, a pakiety nadal nie docierają, należy otworzyć ten sam zakres również w panelu dostawcy.
Informowanie serwera o publicznym adresie IP w środowisku NAT
Uruchom ip -4 addr show na serwerze. Jeśli adres na interfejsie sieciowym jest tym samym, z którym łączą się klienci, pomiń tę sekcję. Jeśli interfejs posiada adres prywatny (10.x, 172.16 do 172.31.x, 192.168.x), a platforma mapuje na niego adres publiczny, serwer nie posiada informacji o swoim publicznym adresie. Dokumentacja vsftpd określa domyślne zachowanie dla pasv_address jako „adres pobierany z przychodzącego gniazda połączenia”, co powoduje, że odpowiedź 227 zawiera adres prywatny, a klient jest kierowany do miejsca, do którego nie ma dostępu.
FileZilla nazywa to ustawienie wprost:
Server sent passive reply with unroutable address. Using server address instead.FileZilla naprawia ten problem automatycznie i kontynuuje działanie. Wiele innych klientów tego nie robi. Próbują one połączyć się z 10.0.0.5 i zawieszają się.
curl również ukrywa ten problem, co ma znaczenie, jeśli curl jest używany do testów. Dokumentacja podaje, że --ftp-skip-pasv-ip „jest domyślnie włączone (dodane w wersji 7.74.0)”, więc curl ignoruje adres w odpowiedzi 227 i ponownie używa adresu połączenia sterującego. Transfer, który działa w curl, może z tego powodu nie działać w kliencie graficznym.
Ustaw adres jawnie. vsftpd przyjmuje pasv_address=203.0.113.10 oraz pasv_addr_resolve=YES (domyślnie NO), jeśli preferowane jest użycie nazwy hosta. ProFTPD przyjmuje MasqueradeAddress, które akceptuje adres IP, nazwę DNS lub nazwę interfejsu. Pure-FTPd przyjmuje -P, udokumentowane dla przypadku, w którym „serwer znajduje się za bramą maskującą (NAT)”. EPSV pozwala uniknąć tego problemu, ponieważ odpowiedź nie zawiera pola adresu, jednak nie można na tym polegać, gdyż to klient decyduje, którą komendę wysłać.
Zmiany w TLS
FTPS to FTP z wykorzystaniem TLS (transport layer security). Klient łączy się z portem 21 w standardowy sposób, wysyła AUTH TLS w celu zabezpieczenia kanału sterowania, a następnie wysyła PROT P, aby zaszyfrować również kanał danych. Zwykły protokół FTP przesyła hasło w postaci otwartego tekstu, dlatego jeśli konieczne jest korzystanie z FTP, należy użyć FTPS. Oprogramowanie vsftpd jest dostarczane z ustawieniem ssl_enable domyślnie ustawionym na NO.
Wynikają z tego dwie kwestie. Żaden mechanizm śledzenia połączeń (connection tracking helper) nie będzie działał, co stanowi drugą stronę powyższego zagadnienia. Ponadto sudo tcpdump -nAi any 'tcp port 21' nie wyświetli już odpowiedzi 227, więc w celu ustalenia, jaki adres i port zostały ogłoszone przez serwer, należy sprawdzić dziennik samego serwera zamiast analizować ruch sieciowy.
Testowanie zmian z zewnątrz
Polecenia należy uruchomić z innej maszyny. Testowanie z poziomu samego serwera pomija firewall, którego konfigurację próbujesz naprawić.
sudo ss -ltnp | grep :21
curl -v --disable-epsv --user ftpuser:secret ftp://example.com/
nc -vz example.com 30000ss powinno wykazać, że demon FTP nasłuchuje na porcie 21. W stanie bezczynności serwera żaden proces nie nasłuchuje w zakresie portów pasywnych, ponieważ gniazda te są tworzone na czas transferu i zamykane bezpośrednio po jego zakończeniu.
--disable-epsv wymusza użycie ścieżki PASV przez curl, która ujawnia problem z adresem. Ślad (trace) wyświetla odpowiedź serwera, a następnie adres i port, z którymi łączy się curl:
< 227 Entering Passive Mode (203,0,113,10,117,52)117 * 256 + 52 = 30004, co mieści się w zadeklarowanym zakresie. Prywatny adres w tej linii oznacza, że pasv_address nie zostało ustawione. Port spoza zakresu oznacza, że serwer nie wczytał zmiany konfiguracji; należy sprawdzić, czy edytowano plik używany przez działającą usługę.
nc samodzielnie odpowiada na pytanie dotyczące firewalla. Natychmiastowe Connection refused oznacza, że pakiet dotarł do serwera i nie znalazł żadnej nasłuchującej usługi, co jest poprawnym wynikiem dla bezczynnego portu pasywnego: reguła działa. Zawieszenie połączenia do momentu, aż nc przerwie operację, oznacza, że coś po drodze cicho odrzuciło pakiet. Jest to firewall – albo ten na serwerze, albo ten w panelu dostawcy. Rozróżnienie to jest identyczne z opisanym w odrzucone kontra przekroczony czas oczekiwania dla SSH i ma zastosowanie do każdego portu.
Czy nadal należy korzystać z FTP?
W przypadku nowych wdrożeń – nie. SFTP (SSH file transfer protocol) działa w ramach pojedynczego połączenia SSH na porcie 22. Nie wymaga drugiego kanału, zakresu portów pasywnych, konfiguracji NAT ani dodatkowego demona do zabezpieczenia, ponieważ funkcjonalność tę zapewnia OpenSSH. sftp user@example.com działa na serwerze, na którym nigdy nie konfigurowano usługi przesyłania plików. Aby udostępnić komuś pliki, ograniczając jednocześnie dostęp użytkownika, sshd_config wykorzystuje ForceCommand internal-sftp wraz z ChrootDirectory. Katalog ten musi być własnością root i nie może być zapisywalny dla użytkownika, w przeciwnym razie sshd odrzuci sesję i zapisze w dzienniku linię bad ownership or modes for chroot directory.
FTP znajduje zastosowanie w sytuacjach, gdy druga strona nie może zmienić konfiguracji. Skanery i urządzenia wielofunkcyjne posiadają oprogramowanie układowe obsługujące wyłącznie FTP. Sprzęt laboratoryjny i przemysłowy często działa na zamkniętym obrazie systemu, którego nikt nie podda ponownej certyfikacji. Partnerzy biznesowi udostępniają serwer FTPS i nie dodadzą innego protokołu dla jednego dostawcy. W każdym z tych przypadków zadanie sprowadza się do konfiguracji zakresu portów pasywnych oraz odpowiednich reguł firewalla, przy czym należy używać wersji FTPS, a nie zwykłego FTP. Architektura dwukanałowa to rozwiązanie z 1985 roku, które obecnie funkcjonuje w środowisku, do którego nie zostało zaprojektowane. Historię tę opisano w historii protokołów przesyłania plików.
FAQ
Dlaczego logowanie FTP przebiega pomyślnie, ale lista plików nie wczytuje się?
Logowanie wykorzystuje wyłącznie połączenie sterujące na porcie 21, które jest dozwolone przez firewall. Lista plików wymaga drugiego połączenia TCP na innym porcie, a to połączenie jest blokowane. Należy zdefiniować zakres portów pasywnych na serwerze FTP i otworzyć ten sam zakres w firewallu, co umożliwi pobranie listy. Zawieszanie się listy plików to problem kanału danych, a nie hasła.
Jakie porty należy otworzyć dla trybu pasywnego FTP?
Port 21 dla kanału sterującego oraz wybrany zakres dla pasywnych połączeń danych. Nie istnieje standardowy zakres, ponieważ konfiguruje się go samodzielnie. Wartość w przedziale od 30000 do 30099 jest odpowiednia: należy dobrać rozmiar zakresu do szczytowej liczby jednoczesnych transferów i upewnić się, że nie pokrywa się on z zakresem portów wychodzących jądra, który można sprawdzić za pomocą sysctl net.ipv4.ip_local_port_range. Jeśli dostawca udostępnia firewall sieciowy w panelu sterowania, należy otworzyć ten sam zakres również tam.
Czy nadal potrzebuję nf_conntrack_ftp?
Nie, a w przypadku nowoczesnych jąder nie można na nim polegać. Automatyczne przypisywanie pomocników (helpers) jest domyślnie wyłączone, a od wersji Linux 6.0 przełącznik net.netfilter.nf_conntrack_helper został usunięty, przez co sysctl zgłasza brak pliku. Dokumentacja ufw uznaje bezwarunkowe ładowanie tych modułów za przestarzałe, a firewalld całkowicie ignoruje AutomaticHelpers. Pomocnik musi również odczytywać kanał sterujący jako czysty tekst, więc przestaje działać w momencie włączenia FTPS. Zamiast tego należy zdefiniować zakres portów pasywnych.
Dlaczego klient FTP zgłasza, że odpowiedź pasywna zawiera adres nieosiągalny?
Serwer odpowiedział PASV adresem, który widzi na własnym interfejsie, a jest to adres prywatny. Dzieje się tak, gdy platforma mapuje adres publiczny na prywatny. Należy jawnie ustawić adres publiczny: pasv_address w vsftpd, MasqueradeAddress w ProFTPD lub -P w Pure-FTPd. FileZilla obchodzi ten problem, ponownie używając adresu, z którym już się połączyła, i loguje komunikat "Using server address instead" – dlatego niektórzy klienci działają mimo błędnej konfiguracji, a inni zawieszają się.
Czy używać FTPS czy SFTP?
SFTP należy stosować wszędzie tam, gdzie obie strony są pod kontrolą: jedno połączenie przez SSH na porcie 22, brak konieczności otwierania kanału danych i gotowość do pracy bez dodatkowej konfiguracji. FTPS to FTP przez TLS, więc zachowuje architekturę dwukanałową i wszystkie związane z nią problemy z firewallem. Należy go wybierać tylko wtedy, gdy druga strona nie obsługuje innego protokołu. Nie należy używać zwykłego FTP przez Internet, ponieważ hasło jest przesyłane w sieci jako czytelny tekst.