protokoły TFTP, FTP, SCP i SFTP do kopiowania plików w Cisco IOS, szyfrowane i nieszyfrowane

Kopiowanie konfiguracji na serwer TFTP to jedna z pierwszych rzeczy, których uczy się administrator sieci. Komenda jest krótka, serwer uruchamiasz i najczęściej nic w nim nie ustawiasz, dwa razy naciskasz Enter i konfiguracja jest skopiowana. Szybko, działa, więc po co cokolwiek zmieniać? Tyle że TFTP nie pyta o hasło, bo w ogóle nie obsługuje uwierzytelniania, a plik przesyła w postaci jawnej. I nie są to jedyne jego ograniczenia.

Opisujemy tu cztery najczęściej używane protokoły do kopiowania plików w IOS: komendy, ograniczenia i to, kiedy który ma sens. Dwa z nich, SCP i SFTP, Cisco dołożyło do wymagań egzaminu CCNA w wersji 2.0.

Cztery protokoły do kopiowania plików w IOS

Podstawowe różnice to transport, uwierzytelnianie i szyfrowanie.

Protokół Transport Uwierzytelnianie Szyfrowanie Router jako serwer
TFTP UDP, port 69 brak brak tak, tylko wskazane pliki
FTP TCP, port 21 login i hasło, przesyłane jawnie brak nie
SCP TCP, port 22 (SSH) jak w SSH tak tak
SFTP TCP, port 22 (SSH) jak w SSH tak nie

Jako klient router obsługuje wszystkie cztery protokoły. Serwer TFTP na routerze udostępnia do pobrania tylko pliki wskazane komendą tftp-server <system-plików>:<plik>. Szczegóły, w tym pozostałe różnice, opisujemy przy poszczególnych protokołach.

SCP i SFTP w CCNA 2.0

Wymagania egzaminu CCNA w wersji 2.0, obowiązującego od 3 lutego 2027 roku, obejmują SFTP i SCP w domenie Network Services and Security. Pozostałe zmiany w egzaminie opisaliśmy w artykule CCNA v2.0 – zmiany w egzaminie od 3 lutego 2027 roku.

TFTP: stary, ale działa

TFTP, czyli Trivial File Transfer Protocol, to w wolnym tłumaczeniu protokół prostego przesyłania plików. Opisuje go RFC 1350 z 1992 roku, a cała specyfikacja mieści się na kilkunastu stronach. Klient prosi o plik albo zgłasza chęć jego wysłania, serwer się zgadza i transfer rusza. Protokół nie przewiduje uwierzytelniania, więc plik może pobrać każdy, kto zna jego nazwę i adres serwera. Dane przesyłane są jawnym tekstem.

Co właściwie wysyłasz

W pliku konfiguracyjnym mogą się znajdować hasze haseł, community stringi SNMP (Simple Network Management Protocol), klucze współdzielone tuneli VPN oraz adresacja interfejsów routera. Kto taki plik przechwyci, dostaje hasze do łamania offline i gotowe klucze.

Wystarczy przechwycić pakiety i z ich zawartości złożyć strumień UDP:

konfiguracja routera Cisco przesłana przez TFTP, widoczna jawnym tekstem w Wiresharku

Cała konfiguracja, gotowa do przeczytania przez każdego, kto ma dostęp do tego odcinka sieci.

Mimo to TFTP jest ciągle używany. Serwer łatwo uruchomić, po stronie klienta nic się nie ustawia, a w wydzielonej sieci zarządzania jawna transmisja nie jest problemem. Bywa też jedynym obsługiwanym protokołem, na przykład w ROMMON (ROM Monitor, tryb rozruchowy routera), gdy po awarii trzeba załadować obraz IOS.

Komendy i zrzuty w tym artykule pochodzą z routera Catalyst 8000V z IOS XE 17.6.3a. Na starszych urządzeniach część z nich może wyglądać inaczej. Różnice, na które trafiliśmy, opisujemy na bieżąco.

Wysłanie bieżącej konfiguracji na serwer TFTP wygląda tak:

Router#copy running-config tftp:
Address or name of remote host []? 192.168.16.120
Destination filename [router-confg]?
!!
5750 bytes copied in 0.766 secs (7507 bytes/sec)
Router#

Urządzenie pyta o dwie rzeczy: dokąd wysłać plik i pod jaką nazwą go zapisać. Serwer nie sprawdza nadawcy: przyjmuje plik i zapisuje go pod podaną nazwą.

pakiet Write Request protokołu TFTP w Wiresharku z widocznym portem 69 i nazwą pliku

Całe żądanie zapisu: numer operacji, nazwa pliku, tryb. Miejsca na dane uwierzytelniające tu nie ma.

Żądanie zapisu (Write Request) zawiera numer operacji, nazwę pliku i tryb przesyłania (octet, czyli binarnie, bez żadnej konwersji). Może jeszcze zawierać opcje, na przykład rozmiar bloku, ale pola na hasło w nim nie ma.

Adres serwera i nazwę pliku można podać od razu w komendzie:

Router#copy running-config tftp://192.168.16.120/konfiguracja.txt
Address or name of remote host [192.168.16.120]?
Destination filename [konfiguracja.txt]?
!!
5750 bytes copied in 0.746 secs (7708 bytes/sec)

Oba pytania nadal padają, tylko odpowiedzi są już podstawione i wystarczy dwa razy nacisnąć Enter. Taka komenda wklejona do skryptu zatrzyma się więc na pierwszym pytaniu i będzie czekać na odpowiedź.

Pytania można wyłączyć, ale nie dla pojedynczej komendy, tylko dla całego urządzenia:

Router(config)#file prompt quiet
Router(config)#exit
Router#copy running-config tftp://192.168.16.120/konfiguracja.txt
!!
5786 bytes copied in 0.680 secs (8509 bytes/sec)

Komendę można teraz wywołać ze skryptu albo z apletu EEM (Embedded Event Manager). Ustawienie zostaje w konfiguracji, dopóki nie cofniesz go poleceniem file prompt alert, więc na sprzęcie produkcyjnym warto włączać je tylko na czas operacji.

Komenda copy obsługuje oba kierunki. Pobranie pliku z serwera to odwrócenie kolejności argumentów:

Router#copy tftp: running-config
Router#copy tftp: startup-config

Pierwsza scala zawartość pliku z konfiguracją już działającą na urządzeniu: polecenia z pliku wykonują się tak, jakbyś wpisywał je z klawiatury, a to, czego w pliku nie ma, zostaje nietknięte. Druga nadpisuje plik konfiguracji startowej, czyli ten, który urządzenie wczyta przy następnym uruchomieniu.

Czy dwukropek po tftp jest wymagany?

Nie. Urządzenie rozpoznaje tftp także bez dwukropka i pyta o adres serwera:

Router#copy running-config tftp
Address or name of remote host []?
?Host name or address not specified
%Error parsing filename (Bad address)

Zapis tftp: oznacza zdalny system plików i nadal warto go stosować, bo jednoznacznie wskazuje, że plik ma trafić do sieci. Bez dwukropka IOS rozpoznaje nazwy protokołów i słowa kluczowe, takie jak running-config czy startup-config, ale każde inne słowo traktuje jako nazwę pliku, a nie miejsce docelowe w sieci:

Router#copy running-config plik
Destination filename [plik]?
6585 bytes copied in 0.448 secs (14699 bytes/sec)
Router#pwd
bootflash:
Router#dir flash: | include plik
35      -rw-             6585  Sep 24 2026 15:43:57 +00:00  plik

Plik o nazwie plik powstał w bieżącym katalogu domyślnego systemu plików, czyli w bootflash:. Transfer przez sieć nie nastąpił, a komenda nie zgłosiła błędu, bo z punktu widzenia IOS-a zrobiła dokładnie to, o co ją poproszono.

Dlaczego TFTP jest wolny i jak go przyspieszyć

TFTP działa w trybie stop-and-wait. Wysyła blok danych, czeka na potwierdzenie, dopiero potem wysyła następny. Domyślny blok ma 512 bajtów.

Widać to na liście pakietów przy żądaniu zapisu (zrzut z Wiresharka wyżej): blok danych, potwierdzenie, blok danych, potwierdzenie. W danej chwili w drodze jest tylko jeden blok, więc w ciągu sekundy przejdzie ich tyle, ile razy zmieści się w niej RTT (round-trip time), czyli czas przejścia pakietu tam i z powrotem:

przepustowość ≈ rozmiar bloku / RTT

Dopóki łącze jest szybsze niż tak wyliczona wartość, o prędkości TFTP decyduje opóźnienie, a nie przepustowość łącza. Sprawdzimy to na większym pliku, o rozmiarze 51 MB, dla dwóch przypadków: serwera w sieci lokalnej i serwera po drugiej stronie tunelu VPN.

topologia pomiaru transferu TFTP i FTP w sieci lokalnej i przez tunel VPN

Wszystkie połączenia w laboratorium mają przepustowość 1 Gb/s. Jedynym wolniejszym odcinkiem jest tunel przez internet.

Najpierw sieć lokalna:

Router#copy flash:c8000v-rpboot.17.06.03a.SPA.pkg tftp://192.168.16.120
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
51449264 bytes copied in 232.490 secs (221297 bytes/sec)

Router#ping 192.168.16.120 repeat 100
Type escape sequence to abort.
Sending 100, 100-byte ICMP Echos to 192.168.16.120, timeout is 2 seconds:
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Success rate is 100 percent (100/100), round-trip min/avg/max = 1/1/14 ms

Pomiar wykonano w sieci lokalnej, na łączu gigabitowym, przy RTT wynoszącym 1 ms. Przesłanie 51 MB zajęło prawie 4 minuty, a efektywna przepustowość wyniosła 221 kB/s, czyli około 1,8 Mb/s. Z gigabitowego łącza protokół wykorzystał 0,18%.

Na jeden blok wypadły 2,3 ms przy RTT równym 1 ms. Ze wzoru wychodzi 512 kB/s, czyli ponad dwa razy więcej. Pozostałą część czasu zajmuje obsługa każdego bloku po obu stronach, więc wzór wyznacza maksymalną prędkość, jakiej można się spodziewać.

Teraz ten sam plik przesłany tunelem VPN przez internet:

Router#copy flash:c8000v-rpboot.17.06.03a.SPA.pkg tftp:
Address or name of remote host []? 10.10.10.129
!!!!.!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
51449264 bytes copied in 3324.734 secs (15475 bytes/sec)

Router#ping 10.10.10.129 repeat 100
Type escape sequence to abort.
Sending 100, 100-byte ICMP Echos to 10.10.10.129, timeout is 2 seconds:
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Success rate is 100 percent (100/100), round-trip min/avg/max = 21/28/181 ms

Transfer trwał 55 minut zamiast 4, a przepustowość spadła do 15,5 kB/s. Wąskim gardłem nie jest tu jednak łącze. Router i serwer mają gigabitowe połączenie ze swoimi bramami, które komunikują się ze sobą tunelem VPN przez internet. To tunel ma najmniejszą przepustowość na ścieżce i odpowiada za niemal całe opóźnienie, więc przepustowość zmierzono właśnie między bramami, w tym samym kierunku co transfer:

[admin@GW-MT] > tool bandwidth-test protocol=udp direction=receive 192.168.20.1
              duration: 1m5s
            rx-current: 173.6Mbps
  rx-10-second-average: 170.6Mbps
      rx-total-average: 120.8Mbps

Przepustowość tunelu przekracza 120 Mb/s, a TFTP wykorzystał z niej 0,1%.

Tym razem obliczona maksymalna przepustowość jest bliska osiąganej. Przy RTT równym 28 ms wychodzi 18,3 kB/s, a zmierzono 15,5 kB/s, czyli o kilkanaście procent mniej. W sieci lokalnej zmierzona wartość była o ponad połowę niższa od obliczonej, bo przy RTT rzędu milisekundy o wyniku decydował narzut związany z obsługą pojedynczego bloku po obu stronach. Im większe opóźnienie, tym mniejsze jest znaczenie tego narzutu.

Na jeden blok wypadły tu 33 ms, czyli o 5 ms więcej niż RTT. Część tej różnicy to ten sam narzut co w sieci lokalnej. Resztę może tłumaczyć to, że ping trwał kilka sekund, a transfer 55 minut, w ciągu których opóźnienie w internecie mogło się zmieniać. Kropka wśród wykrzykników oznacza, że raz trzeba było czekać na timeout i wysłać blok ponownie. Przy 55 minutach transferu jedno takie zdarzenie praktycznie nie zmienia wyniku.

Skutki trybu stop-and-wait łagodzą dwa rozszerzenia protokołu TFTP. RFC 2348 pozwala negocjować większy rozmiar bloku, a RFC 7440 dokłada okno, dzięki któremu można wysłać kilka bloków przed potwierdzeniem. Oba są negocjowane na początku transferu, więc działają tylko wtedy, gdy obsługują je obie strony. W przeciwnym razie transfer odbywa się po staremu, w blokach po 512 bajtów, z potwierdzeniem każdego z nich.

W powyższych transferach nie było używane żadne z tych rozszerzeń: ramki z danymi mają 558 bajtów, czyli 512 bajtów danych plus nagłówki TFTP, UDP, IP i Ethernet. Bloki miały domyślny rozmiar, a odbiór każdego z nich był potwierdzany osobno.

IOS pozwala ustawić większy blok i wówczas transfer tego samego pliku na ten sam serwer w sieci lokalnej wygląda tak:

Router(config)#ip tftp blocksize 8192
Router(config)#exit
Router#copy flash:c8000v-rpboot.17.06.03a.SPA.pkg tftp:
Address or name of remote host []? 192.168.16.120
Destination filename [c8000v-rpboot.17.06.03a.SPA.pkg]?
!!!!!!!!!!!!!!
51449264 bytes copied in 14.996 secs (3430866 bytes/sec)

Zamiast 232 s transfer trwał 15 s, a przepustowość wzrosła z 221 kB/s do 3,4 MB/s. Blok jest 16 razy większy, a wynik lepszy mniej więcej 15,5 raza. Czas przypadający na jeden blok prawie się przy tym nie zmienił: 2,4 ms przy 8192 B wobec 2,3 ms przy 512 B. Liczba wymian z serwerem spadła 16 razy, więc przepustowość wzrosła niemal proporcjonalnie do rozmiaru bloku.

Większy blok router musi najpierw uzgodnić z serwerem. Do żądania zapisu dodaje opcję blksize z wartością 8192, a serwer przyjmuje ją, odsyłając potwierdzenie opcji (OACK, Option Acknowledgment):

negocjacja rozmiaru bloku TFTP w Wiresharku, odpowiedź OACK z blksize 8192 i pierwszy blok danych podzielony na fragmenty IP

Serwer odsyła blksize = 8192, a pierwszy blok danych przechodzi w sześciu fragmentach IP: pięciu po 1514 bajtów i ostatnim, przy którym Wireshark pokazuje złożony pakiet TFTP.

Datagram UDP z 8192 bajtami danych nie mieści się w ramce Ethernet przy MTU (Maximum Transmission Unit) wynoszącym 1500 bajtów, więc zostaje podzielony na fragmenty IP. Część zapór sieciowych odrzuca fragmenty, bo tylko pierwszy z nich zawiera nagłówek UDP z numerami portów. Do tego utrata jednego fragmentu oznacza ponowne wysłanie całego bloku.

W transmisji przez VPN zmiana rozmiaru bloku również poprawiła przepustowość:

Router#copy flash:c8000v-rpboot.17.06.03a.SPA.pkg tftp:
Address or name of remote host []? 10.10.10.129
Destination filename [c8000v-rpboot.17.06.03a.SPA.pkg]?
!!!!!!!!!!!!!!
51449264 bytes copied in 180.744 secs (284653 bytes/sec)

Zamiast 55 minut transfer trwał 3 minuty, a przepustowość wzrosła z 15,5 kB/s do 285 kB/s. Obliczona maksymalna przepustowość dla RTT równego 28 ms to 292 kB/s, więc tym razem zmierzona wartość jest niemal taka sama. Przy dużym opóźnieniu narzut związany z obsługą bloku przestaje się liczyć i zostaje czysty rachunek: rozmiar bloku podzielony przez RTT.

Mechanizm, który tu widać, nie jest specyficzny dla TFTP. Stop-and-wait to skrajny przypadek zależności między przepustowością a opóźnieniem: okno o rozmiarze jednego bloku.

Ograniczenie rozmiaru pliku

Numer bloku w nagłówku TFTP ma dwa bajty, więc maksymalna wartość to 65535. Przy blokach po 512 bajtów daje to około 33,5 MB, a RFC 1350 nie mówi, co ma się stać po osiągnięciu tej granicy.

W praktyce licznik po prostu się przekręca:

przekręcenie 16-bitowego licznika bloków TFTP widoczne w Wiresharku

Po bloku 65535 w nagłówku wraca zero. Wireshark dolicza pełny numer.

W samym pakiecie jest wartość zero, a Wireshark dopisuje obok pełny numer wyliczony z przebiegu transmisji. Obie strony komunikują się dalej bez zakłóceń.

Przekręcanie licznika jest jednak zachowaniem implementacji, a nie częścią standardu, więc obie strony muszą obsługiwać je tak samo. Serwer, który tego nie obsługuje, przerwie transfer.

Plik użyty do pomiaru został podzielony na 100 487 bloków, a transfer zakończył się poprawnie:

ostatni blok transferu TFTP w Wiresharku, krótszy od pozostałych

Ostatnia ramka ma 478 zamiast 558 bajtów. Po tym właśnie odbiorca poznaje koniec pliku.

Ostatni blok jest krótszy od pozostałych. Blok krótszy od ustalonego rozmiaru kończy w TFTP transfer, a ten niesie 432 bajty danych, co razem z nagłówkami TFTP, UDP, IP i Ethernet daje dokładnie 478 bajtów widocznych w kolumnie Length. Gdyby rozmiar pliku był dokładną wielokrotnością rozmiaru bloku (tutaj 512 bajtów), nadawca wysłałby na koniec blok bez danych.

FTP: szybciej i z uwierzytelnianiem, ale bez szyfrowania

FTP (File Transfer Protocol) opiera się na TCP, a to zdejmuje ograniczenie przepustowości TFTP. TCP nie potwierdza osobno każdego otrzymanego segmentu, a nadawca może wysyłać kolejne segmenty, zanim otrzyma potwierdzenia dla poprzednich. Ile ich może być w drodze jednocześnie, wyznaczają dwa okna: okno przeciążenia po stronie nadawcy i okno rozgłaszane przez odbiorcę. Szczegóły tego mechanizmu wykraczają poza ten artykuł. Dopóki okna pozostają odpowiednio duże w stosunku do iloczynu przepustowości i opóźnienia, łącze da się wysycić.

Różnicę względem TFTP widać na tym samym pliku, wysłanym do tych samych dwóch serwerów co wcześniej:

Router#copy flash:c8000v-rpboot.17.06.03a.SPA.pkg ftp:
Address or name of remote host []? 192.168.16.120
Destination filename [c8000v-rpboot.17.06.03a.SPA.pkg]?
Writing c8000v-rpboot.17.06.03a.SPA.pkg !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
51449264 bytes copied in 12.313 secs (4178451 bytes/sec)

Router#copy flash:c8000v-rpboot.17.06.03a.SPA.pkg ftp:
Address or name of remote host []? 10.10.10.129
Destination filename [c8000v-rpboot.17.06.03a.SPA.pkg]?
Writing c8000v-rpboot.17.06.03a.SPA.pkg !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
51449264 bytes copied in 57.094 secs (901133 bytes/sec)

W sieci lokalnej przesłanie 51 MB zajęło 12 s zamiast 232 s, czyli FTP był około 19 razy szybszy od TFTP z domyślnym blokiem. Przez VPN różnica jest jeszcze większa: 57 s zamiast 55 minut, prawie 60 razy szybciej. Zgadza się to z tym, co opisaliśmy wyżej, bo TFTP traci najwięcej właśnie tam, gdzie RTT jest duże.

Transfer 51 MB Sieć lokalna (RTT 1 ms) VPN (RTT 28 ms)
TFTP, blok 512 B 232 s, 221 kB/s 3325 s, 15,5 kB/s
TFTP, blok 8192 B 15 s, 3,4 MB/s 181 s, 285 kB/s
FTP 12 s, 4,2 MB/s 57 s, 0,9 MB/s

Przez VPN FTP pozostaje ponad trzy razy szybszy od TFTP z dużym blokiem, bo TFTP nadal czeka na potwierdzenie każdego bloku, a przy 28 ms każde takie czekanie kosztuje. W sieci lokalnej TFTP z blokiem 8192 B prawie dogonił FTP, ale tylko dlatego, że FTP działał tu z ograniczeniem, które widać dopiero w Wiresharku.

Segmenty danych FTP niosą po 536 bajtów, choć w Ethernecie zmieściłoby się 1460. Tyle wynosi domyślny MSS (Maximum Segment Size, maksymalna ilość danych w jednym segmencie TCP), którego IOS używa w połączeniach nawiązywanych przez sam router z adresem spoza bezpośrednio podłączonej sieci. Serwer w naszym labie jest w innej podsieci niż router. Wartość 536 bajtów jest bezpieczna na każdej ścieżce, ale każdy segment niesie niecałe 40% tego, co mógłby.

Większy MSS router dobierze sam po włączeniu mechanizmu wykrywania MTU ścieżki (Path MTU Discovery, PMTUD), który w IOS jest domyślnie wyłączony:

Router(config)#do show running-config all | include ip tcp path
no ip tcp path-mtu-discovery
Router(config)#ip tcp path-mtu-discovery
Router(config)#exit
Router#copy flash:c8000v-rpboot.17.06.03a.SPA.pkg ftp:
Address or name of remote host []? 192.168.16.120
Destination filename [c8000v-rpboot.17.06.03a.SPA.pkg]?
Writing c8000v-rpboot.17.06.03a.SPA.pkg !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
51449264 bytes copied in 5.558 secs (9256795 bytes/sec)

Ten sam transfer trwał 5,6 s zamiast 12,3 s, a przepustowość wzrosła ponad dwukrotnie. Przez VPN efekt jest podobny: 26 s zamiast 57 s. Path MTU Discovery działa tylko wtedy, gdy po drodze nikt nie blokuje komunikatów ICMP „Fragmentation needed”, bo to z nich nadawca dowiaduje się, że pakiet jest za duży. Szczegóły opisuje dokumentacja Cisco do konfiguracji TCP.

Same wartości bezwzględne mogą dziwić, bo nawet 9,3 MB/s, czyli około 74 Mb/s, na łączu gigabitowym to niewiele. Ograniczeniem nie jest tu łącze, ale co dokładnie hamuje transfer, nie badaliśmy. Pakiety tranzytowe, które tylko przechodzą przez router, obsługuje płaszczyzna danych (data plane) przystosowana do szybkiego przełączania. Ruch, którego nadawcą lub odbiorcą jest sam router, przechodzi przez płaszczyznę sterowania (control plane) i stos TCP systemu, a ta droga jest znacznie wolniejsza. Przepustowość przy kopiowaniu plików na router i z routera bywa więc wyraźnie niższa niż dla ruchu tranzytowego.

Dwa połączenia zamiast jednego

FTP zestawia dwa połączenia TCP:

  • sterujące, na port 21, które trwa przez całą sesję i przenosi tylko polecenia FTP i odpowiedzi serwera,
  • danych, zestawiane na czas transmisji i służące wyłącznie do przesłania zawartości pliku.

Połączenie do transmisji danych może być inicjowane przez serwer (tryb aktywny) lub przez klienta (tryb pasywny). W trybie aktywnym serwer zgodnie z RFC 959 otwiera je ze swojego portu 20. W pasywnym port 20 nie jest używany, a numer portu, na który klient ma się połączyć, serwer podaje w odpowiedzi na polecenie PASV. NAT i firewalle przepuszczają zwykle połączenia wychodzące od klienta, a przychodzące do niego blokują. Jeśli klient jest za NAT lub firewallem, tryb aktywny może nie działać.

Klient FTP w IOS domyślnie korzysta z trybu pasywnego.

tryb pasywny FTP w Wiresharku, polecenie PASV i odpowiedź serwera z adresem i portem

W odpowiedzi na polecenie PASV serwer podaje adres i port, a połączenie danych otwiera klient.

Tryb aktywny włącza się komendą no ip ftp passive. Przydaje się na przykład wtedy, gdy serwer jest za firewallem, który przepuszcza do niego tylko port 21.

tryb aktywny FTP w Wiresharku, polecenie PORT z adresem i portem klienta

Tym razem to klient podaje swój adres i port, a połączenie danych otwiera serwer.

W trybie aktywnym klient przekazuje swój adres i port poleceniem PORT, zapisując je jako sześć liczb: cztery pierwsze to adres IP, a dwie ostatnie to numer portu rozbity na dwa bajty. PORT 192,168,20,137,204,96 oznacza więc port 204 × 256 + 96 = 52320. Tak samo serwer zapisuje adres i port w odpowiedzi na PASV.

Protokół FTP ma też polecenia do zarządzania plikami na serwerze: listowanie katalogu, usuwanie pliku lub zmianę jego nazwy. Klient w IOS ich nie obsługuje. Komendy dir i delete przyjmują tylko lokalne systemy plików, a ftp: do nich nie należy. Z poziomu IOS-a FTP daje więc w tej kwestii tyle samo co TFTP: plik można zapisać w istniejącym katalogu na serwerze, podając ścieżkę w nazwie pliku docelowego:

Router#copy flash:c8000v-rpboot.17.06.03a.SPA.pkg ftp:
Address or name of remote host []? 192.168.16.120
Destination filename [c8000v-rpboot.17.06.03a.SPA.pkg]? abc/c8000v-rpboot.17.06.03a.SPA.pkg
Writing abc/c8000v-rpboot.17.06.03a.SPA.pkg !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
51449264 bytes copied in 5.633 secs (9133546 bytes/sec)

Hasło przesyłane jawnie

Serwer FTP wymaga uwierzytelniania nazwą użytkownika i hasłem. Na kliencie IOS dane logowania ustawia się globalnie:

Router(config)#ip ftp username qwerty
Router(config)#ip ftp password 12345

Każde odwołanie do ftp: korzysta z tych poświadczeń, więc samo kopiowanie nie wymaga podawania ich ponownie:

Router#copy running-config ftp:
Address or name of remote host []? 192.168.16.120
Destination filename [router-confg]?
Writing router-confg !
5977 bytes copied in 0.753 secs (7938 bytes/sec)

Pytania są te same co przy TFTP: adres serwera i nazwa pliku.

Poświadczenia można też podać bezpośrednio w adresie:

Router#copy flash:c8000v-rpboot.17.06.03a.SPA.pkg ftp://qwerty:12345@192.168.16.120/c8000v-rpboot.17.06.03a.SPA.pkg
Address or name of remote host [192.168.16.120]?
Destination filename [c8000v-rpboot.17.06.03a.SPA.pkg]?
Writing c8000v-rpboot.17.06.03a.SPA.pkg !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
51449264 bytes copied in 7.555 secs (6809962 bytes/sec)

Ruch na połączeniu sterującym i na połączeniu danych nie jest jednak szyfrowany, więc kto go przechwyci, odczyta login, hasło i przesyłane dane:

login i hasło FTP przesłane jawnym tekstem, widoczne w Wiresharku

Cała sesja sterująca, łącznie z loginem i hasłem, jest czytelna.

Hasło ustawione komendą ip ftp password trafia też do konfiguracji routera, a więc do pliku, który przez FTP kopiujemy na serwer. Kopia konfiguracji zawiera wtedy dane logowania do serwera, na którym jest przechowywana:

konfiguracja routera Cisco przesłana przez FTP, polecenie ip ftp password z hasłem widoczne jawnym tekstem w Wiresharku

To samo hasło jeszcze raz, tym razem w treści wysyłanego pliku.

FTP rozwiązuje zatem dwa problemy TFTP: lepiej wykorzystuje przepustowość łącza i uwierzytelnia użytkownika. Transmisja pozostaje jednak jawna.

SCP: kopiowanie przez SSH

SCP (Secure Copy Protocol) przesyła plik wewnątrz sesji SSH (Secure Shell), więc login, hasło i zawartość pliku są szyfrowane. Poza tym pod względem możliwości jest równie prosty jak TFTP: przesyła plik w jedną albo drugą stronę. Nie obsługuje listowania katalogów ani usuwania plików.

Router z IOS XE może działać jako klient lub serwer SCP.

Router jako klient SCP

Polecenie wygląda tak samo jak przy poprzednich protokołach. Tym razem urządzenie pyta dodatkowo o nazwę użytkownika i hasło na serwerze:

Router#copy running-config scp:
Address or name of remote host []? 192.168.16.120
Destination username [Router]? student
Destination filename [router-confg]?
Writing router-confg
Password:
 Sink: C0644 6498 router-confg
!
6498 bytes copied in 3.984 secs (1631 bytes/sec)

W sesji SCP jawnie przesyłane są tylko nazwy i wersje oprogramowania klienta i serwera, listy obsługiwanych algorytmów kryptograficznych oraz dane potrzebne do uzgodnienia szyfrowania: klucz publiczny serwera i wartości Diffie-Hellmana. Na podstawie list algorytmów klient i serwer negocjują, których użyją. Wszystko, co następuje potem, w tym login, hasło i zawartość pliku, jest już zaszyfrowane:

sesja SCP przechwycona w Wiresharku, zaszyfrowana transmisja SSH

Czytelne są tylko nazwy i wersje oprogramowania oraz nazwy algorytmów. Hasła i pliku tu nie znajdziesz.

W przeciwieństwie do FTP całość idzie jednym połączeniem TCP na port 22, bez osobnego połączenia danych. Zaraz po jego zestawieniu obie strony przedstawiają się nazwą i wersją oprogramowania, jako pierwszy serwer:

zestawienie połączenia TCP na port 22 i wymiana banerów SSH przy kopiowaniu przez SCP w Wiresharku

Jedno połączenie na port 22, a na jego początku banery serwera i klienta.

SCP jest przy tym wolniejszy od FTP. Ten sam plik, który przez FTP (z włączonym ip tcp path-mtu-discovery) trafił na serwer w 5,6 s, przez SCP dotarł tam po 14,4 s:

Router#copy flash:c8000v-rpboot.17.06.03a.SPA.pkg scp:
Address or name of remote host []? 192.168.16.120
Destination username [Router]? student
Destination filename [c8000v-rpboot.17.06.03a.SPA.pkg]?
Writing c8000v-rpboot.17.06.03a.SPA.pkg
Password:
 Sink: C0644 51449264 c8000v-rpboot.17.06.03a.SPA.pkg
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
51449264 bytes copied in 14.407 secs (3571130 bytes/sec)

Plik z serwera pobiera się tym samym poleceniem copy, podając scp: jako źródło:

Router#copy scp: flash:
Address or name of remote host []? 192.168.16.120
Source username [Router]? student
Source filename []? router-confg
Destination filename [router-confg]? backup.cfg
Password:
 Sending file modes: C0666 6498 router-confg
!
6498 bytes copied in 3.915 secs (1660 bytes/sec)

Do roli klienta router nie potrzebuje lokalnie działającego serwera SSH. Polecenie crypto key zeroize rsa usuwa wszystkie klucze RSA i tym samym wyłącza serwer SSH na routerze, a klient SCP działa dalej:

Router#crypto key zeroize rsa
% All keys will be removed.
% All router certs issued using these keys will also be removed.
Do you really want to remove these keys? [yes/no]: yes
*Sep 24 08:59:16.503: %CRYPTO_ENGINE-5-KEY_DELETED: A key named TP-self-signed-3747523412 has been removed from key storage
*Sep 24 08:59:16.505: %CRYPTO_ENGINE-5-KEY_DELETED: A key named TP-self-signed-3747523412.server has been removed from key storage
*Sep 24 08:59:16.513: %SSH-5-DISABLED: SSH 1.99 has been disabled
Router#copy running-config scp:
Address or name of remote host []? 192.168.16.120
Destination username [Router]? student
Destination filename [router-confg]?
Writing router-confg
Password:
 Sink: C0644 4540 router-confg
!
4540 bytes copied in 2.924 secs (1553 bytes/sec)

To test laboratoryjny. Na routerze produkcyjnym crypto key zeroize rsa odcina logowanie przez SSH i usuwa certyfikaty wystawione dla tych kluczy, w tym samopodpisany certyfikat serwera HTTPS.

Router jako serwer SCP

W tej roli router musi mieć działający serwer SSH. Na Catalyst 8000V z IOS XE 17.6.3a serwer SSH jest domyślnie włączony. Korzysta z pary kluczy RSA, którą urządzenie generuje automatycznie dla samopodpisanego (ang. self-signed) certyfikatu serwera HTTPS (w konfiguracji jest ip http secure-server):

Router#show ip ssh
SSH Enabled - version 1.99
...
IOS Keys in SECSH format(ssh-rsa, base64 encoded): TP-self-signed-3747523412
Modulus Size : 2048 bits

Bez kluczy serwer SSH nie działa także na Catalyst 8000V, co było widać po crypto key zeroize rsa. Różnica polega tylko na tym, czy klucze zostały wygenerowane automatycznie. Na naszym routerze Cisco 1900 z IOS 15.6 ich nie było, więc SSH było wyłączone:

Router#show ip ssh
SSH Disabled - version 1.99
%Please create RSA keys to enable SSH (and of atleast 768 bits for SSH v2).

W takiej sytuacji klucze trzeba wygenerować poleceniem crypto key generate rsa.

Wersja 1.99 oznacza, że serwer przyjmuje połączenia zarówno w starej wersji 1 protokołu SSH, jak i w wersji 2. Komenda ip ssh version 2 wyłącza wersję 1 i warto ją wpisać ze względów bezpieczeństwa.

Do logowania potrzebne jest jeszcze konto lokalne i uwierzytelnianie na liniach wirtualnych używające lokalnych użytkowników. Komenda transport input ssh zezwala na liniach wirtualnych wyłącznie na SSH. Domyślne ustawienie zależy od platformy i wersji systemu, a jeśli jest nim none, bez tej komendy połączenie SSH będzie odrzucone:

Router(config)#username admin secret cisco
Router(config)#line vty 0 4
Router(config-line)#login local
Router(config-line)#transport input ssh

Samo SSH nie wystarczy, żeby skopiować plik na router. Kolejne braki w konfiguracji widać w komunikatach po stronie komputera. Pierwsza próba, z Windowsa z OpenSSH 9.5:

PS C:\Users\csp-s> scp -O .\router-confg admin@192.168.20.137:
(admin@192.168.20.137) Password:
Administratively disabled.

Logowanie się udało, ale serwer SCP jest domyślnie wyłączony. Włącza go komenda ip scp server enable. Po niej komunikat się zmienia:

Router(config)#ip scp server enable

PS C:\Users\csp-s> scp -O .\router-confg admin@192.168.20.137:
(admin@192.168.20.137) Password:
Privilege denied.

Kopiować przez SCP może tylko użytkownik z najwyższym poziomem uprawnień, czyli 15. Konto admin loguje się przez SSH bez problemu, ale ma domyślny poziom 1. Po nadaniu mu poziomu 15 komunikat znów się zmienia:

Router(config)#username admin privilege 15 secret cisco

PS C:\Users\csp-s> scp -O .\router-confg admin@192.168.20.137:
(admin@192.168.20.137) Password:
router-confg                                    0%    0     0.0KB/s   --:-- ETAWrite failed

Uprawnienia już wystarczają, ale nie podaliśmy nazwy pliku na routerze. Sam dwukropek oznacza katalog domowy użytkownika, więc klient przekazuje jako ścieżkę docelową kropkę, a IOS nie potrafi otworzyć jej do zapisu. Widać to w wyniku debug ip scp:

*Sep 24 09:29:11.409: SCP: Path received .
*Sep 24 09:29:11.410: SCP: Sanitized Path .
...
*Sep 24 09:29:11.427: SCP: [22 -> 192.168.16.120:49783] send Not able to open file
*Sep 24 09:29:11.427: SCP: [22 -> 192.168.16.120:49783] send Write failed

Z pełną ścieżką plik trafia do katalogu głównego pamięci flash:

PS C:\Users\csp-s> scp -O .\router-confg admin@192.168.20.137:/backup-scp.cfg
(admin@192.168.20.137) Password:
router-confg                                  100% 4540   233.4KB/s   00:00

Router#dir flash: | include backup
32      -rw-             4540  Sep 24 2026 09:35:10 +00:00  backup-scp.cfg

We wszystkich powyższych poleceniach scp pojawia się parametr -O. Od wersji 9.0 OpenSSH polecenie scp domyślnie używa protokołu SFTP, a nie klasycznego protokołu SCP. Parametr -O przywraca stary protokół. IOS XE nie ma serwera SFTP, więc bez tego parametru połączenie kończy się zaraz po zalogowaniu, bez komunikatu o przyczynie (Cisco opisuje ten problem w osobnym dokumencie):

PS C:\Users\csp-s> scp .\router-confg admin@192.168.20.137:/backup-scp-2.cfg
(admin@192.168.20.137) Password:
Connection to 192.168.20.137 closed by remote host.
C:\Windows\System32\OpenSSH\scp.exe: Connection closed

Router odnotowuje udane logowanie i nic więcej. debug ip scp niczego nie pokazuje, bo klient poprosił o SFTP, a nie o SCP. Parametr -O jest potrzebny w każdym kliencie OpenSSH od wersji 9.0, czyli w praktyce w aktualnych wersjach Windowsa, macOS i większości dystrybucji Linuksa.

Dokumentacja Cisco dla przełączników Catalyst wymienia jako warunek działania serwera SCP konfigurację AAA (Authentication, Authorization and Accounting). Na Catalyst 8000V z IOS XE 17.6.3a nie jest ona potrzebna: wystarczyły konto lokalne z poziomem 15, login local i transport input ssh na liniach wirtualnych oraz ip scp server enable.

SFTP: w IOS tylko klient

SFTP (SSH File Transfer Protocol) to osobny protokół, który podobnie jak SCP działa wewnątrz sesji SSH, ale ma więcej możliwości: pozwala wylistować katalog na serwerze, skasować plik, zmienić mu nazwę albo wznowić przerwany transfer. Klient w IOS jednak ich nie obsługuje. Tak jak przy FTP, komendy dir i delete nie przyjmują sftp:, więc klient potrafi wyłącznie kopiować pliki:

Router#copy running-config sftp:
Address or name of remote host []? 192.168.16.120
Destination username [Router]? student
Destination filename [router-confg]? router-confg-sftp
Password:

SFTP send: Writing to /C:/Users/student/router-confg-sftp size 6498
!
6498 bytes copied in 3.347 secs (1941 bytes/sec)

Pytania są te same co przy SCP. IOS wyświetla też pełną ścieżkę pliku na serwerze, tutaj w katalogu domowym użytkownika student.

Pobieranie pliku działa analogicznie. Login, hasło i ścieżkę można też podać w adresie, co przydaje się w skryptach:

Router#copy sftp://student:student@192.168.16.120/router-confg-sftp flash:/router-confg-sftp-3
Destination filename [router-confg-sftp-3]?
!
4540 bytes copied in 0.761 secs (5966 bytes/sec)

Klient SFTP nie potrzebuje działającego serwera SSH na routerze: po usunięciu kluczy RSA kopiowanie przez SFTP działało tak samo jak przez SCP. Dokumentacja Cisco dla przełączników Catalyst wymienia jako warunek skonfigurowanie ip ssh source-interface. Na Catalyst 8000V z IOS XE 17.6.3a klient tego nie wymaga.

Transmisja pliku 51 MB przez VPN (RTT 28 ms) trwała przez SCP 62 s, a przez SFTP ponad 8 minut, czyli dłużej niż przez TFTP z blokiem 8192 B. Szyfrowanie ukrywa treść transmisji, ale nie jej rytm, więc przyczynę widać na wykresie przepływu w Wiresharku:

klient SFTP na Cisco IOS czeka na odpowiedź serwera po każdej porcji danych, wykres przepływu w Wiresharku

Porcja danych, cisza, krótka odpowiedź serwera i dopiero wtedy następna porcja.

Router wysyła porcję około 8 kB danych w kilku segmentach TCP i milknie, dopóki serwer nie odpowie krótkim komunikatem, najpewniej potwierdzeniem zapisu. Dopiero wtedy wysyła kolejną porcję. Jest to więc ten sam schemat stop-and-wait co w TFTP, tylko realizowany przez klienta SFTP ponad TCP. Sam protokół SFTP pozwala wysyłać kolejne żądania zapisu bez czekania na odpowiedzi na poprzednie (specyfikacja IETF), ale klient w IOS z tego nie korzysta. W naszym pomiarze odpowiedź serwera przychodziła po około 60 ms, a nie po 28 ms, więc część opóźnienia wynika z przetwarzania danych na serwerze.

Dla porównania SCP na tym samym łączu nie czeka na odpowiedzi serwera. Serwer odsyła wyłącznie potwierdzenia TCP. W drodze jest naraz około 19 kB danych, a nie jedna porcja 8 kB:

SCP na Cisco IOS wysyła dane bez oczekiwania na odpowiedź serwera, wykres przepływu w Wiresharku

Od serwera przychodzą tylko potwierdzenia TCP, a router nie wstrzymuje się w oczekiwaniu na odpowiedź.

W IOS XE nie ma serwera SFTP. Przez SFTP router może więc wyłącznie wysyłać pliki na serwer lub pobierać je z serwera.

SFTP to nie FTPS ani FTP przez SSH

Podobne nazwy kryją trzy różne rozwiązania.

SFTP działa wewnątrz sesji SSH, tak samo jak SCP. Z FTP łączy go tylko nazwa: nie używa poleceń FTP ani osobnego połączenia danych, a całość przesyłana jest jednym połączeniem TCP na port 22.

FTPS to klasyczny FTP, w którym połączenie sterujące i połączenia danych szyfruje TLS (RFC 4217). Zostają dwa połączenia i wszystkie kłopoty FTP z NAT-em i firewallami. Dochodzi nowy: klient i serwer uzgadniają port połączenia danych w zaszyfrowanym połączeniu sterującym. Firewall nie zna więc tego portu i nie wie, że ma przepuścić połączenie danych.

FTP przez SSH to zwykły FTP, którego połączenie sterujące przekierowano przez tunel SSH. Połączenia danych zestawiane są osobno, na portach wskazanych przez serwer, i jeśli nie przekieruje się ich specjalnie, do tunelu nie trafiają. Login i hasło są więc chronione, a przesyłane pliki już nie.

Skrót SFTP ma jeszcze jedno znaczenie. Tak nazywał się Simple File Transfer Protocol z RFC 913 z 1984 roku, dziś zapomniany.

Co wybrać w praktyce

W środowiskach niezaufanych używaj SCP. TFTP i FTP zostaw do laboratorium i do wydzielonej, zaufanej sieci zarządzania.

Tabela zbiera wszystkie pomiary z artykułu: ten sam plik, ten sam router i te same serwery, w sieci lokalnej oraz przez VPN. Na innej platformie wartości będą inne, dlatego porównuj raczej proporcje niż liczby bezwzględne.

Transfer 51 MB Sieć lokalna (RTT 1 ms) VPN (RTT 28 ms)
TFTP, blok 512 B 232 s, 221 kB/s 3325 s, 15,5 kB/s
TFTP, blok 8192 B 15 s, 3,4 MB/s 181 s, 285 kB/s
FTP, bez PMTUD 12 s, 4,2 MB/s 57 s, 0,9 MB/s
FTP, z PMTUD 5,6 s, 9,3 MB/s 26 s, 2,0 MB/s
SCP, z PMTUD 14 s, 3,6 MB/s 62 s, 0,8 MB/s
SFTP, z PMTUD 26 s, 2,0 MB/s 482 s, 107 kB/s

Z tych pomiarów i z tego, co zobaczyliśmy po drodze, wynikają cztery wnioski:

  1. SCP to rozsądny wybór domyślny. Szyfruje login, hasło i zawartość pliku, a w naszych pomiarach był wyraźnie szybszy od SFTP. Router może być zarówno klientem, jak i serwerem SCP.
  2. SFTP w IOS nie daje przewagi nad SCP, jeśli serwer obsługuje oba protokoły. Klient potrafi wyłącznie kopiować pliki, a jego implementacja jest wolna, zwłaszcza przy większym opóźnieniu.
  3. TFTP i FTP przesyłają wszystko jawnie, ale w zaufanej sieci można ich używać. Warto wtedy w TFTP zwiększyć blok poleceniem ip tftp blocksize 8192.
  4. Polecenie ip tcp path-mtu-discovery warto włączyć praktycznie zawsze. Dotyczy wszystkich połączeń TCP nawiązywanych przez router. W przypadku FTP skróciło transfer ponad dwukrotnie, zarówno w sieci lokalnej, jak i przez VPN.

Ręczne copy to dopiero początek. IOS potrafi sam wysyłać kopię konfiguracji na zdalny serwer po każdym zapisie (archive) i wycofać zmianę bez restartu urządzenia (configure replace). Kopie z archive można zapisywać przez każdy z czterech opisanych protokołów, więc wybór między nimi dotyczy także kopii tworzonych automatycznie.

Na szkoleniu CCNA przesyłanie plików przez te protokoły ćwiczymy na fizycznych routerach i przełącznikach, w sali szkoleniowej, do której łączysz się zdalnie. Jeśli chcesz przećwiczyć to z instruktorem, zapraszamy na szkolenie.

Jedyne w Polsce szkolenie CCNA ,
gdzie pracujesz ZDALNIE na prawdziwym,
FIZYCZNYM sprzęcie sieciowym.

Ściąga z komendami

Wszystkie komendy z artykułu w jednym miejscu, pogrupowane według protokołu. Sprawdzone na Catalyst 8000V z IOS XE 17.6.3a.

! TFTP
Router#copy running-config tftp:
Router#copy running-config tftp://<serwer>/<plik>
! scala plik z bieżącą konfiguracją
Router#copy tftp: running-config
! nadpisuje konfigurację startową
Router#copy tftp: startup-config
! większy blok, jeśli serwer go obsługuje
Router(config)#ip tftp blocksize 8192
! router jako serwer TFTP, udostępnia wskazany plik do pobrania
Router(config)#tftp-server <system-plików>:<plik>

! FTP
Router(config)#ip ftp username <użytkownik>
Router(config)#ip ftp password <hasło>
Router#copy running-config ftp:
Router#copy running-config ftp://<użytkownik>:<hasło>@<serwer>/<plik>
! dotyczy wszystkich połączeń TCP nawiązywanych przez router
Router(config)#ip tcp path-mtu-discovery

! SCP, router jako klient
Router#copy running-config scp:
Router#copy scp: flash:

! SCP, router jako serwer
Router(config)#username <użytkownik> privilege 15 secret <hasło>
Router(config)#line vty 0 4
Router(config-line)#login local
Router(config-line)#transport input ssh
Router(config-line)#exit
Router(config)#ip ssh version 2
Router(config)#ip scp server enable
! kopiowanie z komputera na router (OpenSSH 9.0 i nowszy)
PS C:\> scp -O <plik> <użytkownik>@<router>:/<plik>

! SFTP, router jako klient
Router#copy running-config sftp:
Router#copy sftp://<użytkownik>:<hasło>@<serwer>/<plik> flash:/<plik>

! Wyłączenie i przywrócenie pytań przy kopiowaniu
Router(config)#file prompt quiet
Router(config)#file prompt alert

! Diagnostyka
Router#show ip ssh
Router#debug tftp events
Router#debug tftp packets
Router#debug ip ftp
Router#debug ip scp
Router#debug ip sftp
Router#undebug all

Automatyczne kopie konfiguracji i wycofywanie zmian poleceniem configure replace to temat na kolejny artykuł.