Các giao thức truyền tệp từ Kermit đến rsync
Kermit vừa tròn 45 tuổi và có bản phát hành mới. Xem lịch sử truyền tệp từ đường dây điện thoại nhiễu, FTP sau NAT đến lý do rsync và SFTP thắng.
Vì sao các giao thức truyền tệp liên tục thay đổi
Mỗi giao thức truyền tệp được thiết kế để xử lý một kiểu lỗi đặc trưng của thời đại nó ra đời. Kermit giả định đường truyền sẽ làm hỏng các byte của bạn. XMODEM và ZMODEM giả định kết nối chậm và mỗi phút kết nối đều phát sinh chi phí. FTP (file transfer protocol) giả định mạng trung gian hoạt động đáng tin cậy. SSH giả định mạng đó không đáng tin cậy. Giả định cuối cùng đã thắng. Vì vậy, VPS ngày nay cung cấp SFTP và rsync qua SSH, còn lại rất ít lựa chọn khác.
Hiện nay là thời điểm thích hợp để xem lại vấn đề này. C-Kermit 11.0.506 được phát hành vào 3 August 2026. Đây là bản phát hành không beta đầu tiên kể từ C-Kermit 9.0.302 vào 20 August 2011, trong khi giao thức mà nó triển khai được thiết kế vào May 1981. Bốn mươi lăm năm đủ dài để chứng kiến cả một nhóm công nghệ được phát minh, chuẩn hóa, bị chính mạng mà nó chạy trên đó làm cho không còn phù hợp, rồi được tích hợp vào SSH.
Kermit, 1981: được thiết kế cho đường truyền làm hỏng byte
Kermit được tạo ra vào tháng 5 năm 1981 tại Columbia University Computer Center bởi Frank da Cruz và Bill Catchings. Tên này bắt nguồn từ Kermit the Frog. Theo lời kể của da Cruz, một cuốn lịch Muppets treo trên tường khi nhóm đang cố nghĩ tên, và không ai ngờ phần mềm này lại được sử dụng rộng rãi.
Kermit không được tạo ra để giải quyết vấn đề tốc độ. Đường truyền giữa terminal và mainframe không phải là một pipe truyền được mọi byte tùy ý. Đó là một character device có các giới hạn riêng. Nó có thể chỉ hỗ trợ 7-bit. Nó có thể hoạt động ở chế độ half duplex. Nó có thể nuốt control character hoặc xử lý một control character như một lệnh. Gửi trực tiếp một binary file qua đó sẽ không hoạt động.
Vì vậy, thiết kế của Kermit tuân thủ đúng các giới hạn này. Lịch sử do Kermit Project công bố liệt kê các điểm sau:
- packet ngắn, vì phần lớn mainframe không thể nhận các đợt dữ liệu đến dài từ terminal
- half-duplex stop-and-wait, vì IBM mainframe không hỗ trợ giao tiếp full-duplex
- mã hóa có thể in được cho control character và ký tự 8-bit, vì cả hai loại này đều không thể đi qua terminal driver của mainframe
- checksum trong mọi packet, do bên nhận phản hồi, để một packet bị hỏng chỉ cần truyền lại một lần thay vì phải truyền lại cả file
Điểm thứ ba là điểm đáng chú ý. Kermit gửi một bản mã hóa an toàn với text của file thay vì gửi chính file đó. Một control byte được chuyển thành một prefix character theo sau bởi một ký tự có thể in được; byte có bit cao được bật cũng có thể mã hóa theo cách tương tự để truyền qua link 7-bit. Bất kỳ thành phần trung gian nào chỉ hiểu text có thể in được sẽ chỉ thấy text có thể in được. Đổi lại là kích thước: binary file sẽ lớn hơn khi truyền trên đường truyền. Với một mainframe front end nếu không sẽ làm hỏng hoàn toàn quá trình truyền, đây là sự đánh đổi phù hợp.
Một đặc điểm khác thường của Kermit là phạm vi sử dụng. XMODEM truyền file giữa hai máy đã thống nhất với nhau về khái niệm file. Kermit được viết như một mẫu số chung nhỏ nhất giữa các hệ thống không thống nhất với nhau, có character set khác nhau, record structure khác nhau và cách xác định kết thúc một dòng text khác nhau. Đây là thế giới được mô tả trong quá trình chuyển đổi dài từ mainframe sang cloud server, và Kermit cho thấy khả năng tương tác đã được thực hiện như thế nào trước khi network layer xử lý việc đó thay bạn.
Columbia chấm dứt tài trợ vào năm 2011 và phát hành C-Kermit theo revised 3-clause BSD licence. Frank da Cruz gắn bó với dự án trong 44 năm, từ thiết kế năm 1981 đến năm 2025. Bản phát hành năm 2026 do OpenKermit project duy trì, với John Goerzen thực hiện công việc hiện đại hóa một codebase C cũ hơn phần lớn những người đang đọc nó.
XMODEM và ZMODEM: khi cước điện thoại định hình thiết kế
Ward Christensen viết MODEM.ASM vào năm 1977, và protocol mà chương trình này giới thiệu là XMODEM. Năm 1978, ông và Randy Suess đưa CBBS lên mạng, trở thành bulletin board system công khai đầu tiên. Christensen qua đời ngày 11 October 2024.
XMODEM gần như là một protocol tối giản nhất có thể. Dữ liệu được truyền theo các block 128 byte. Mỗi block có một checksum 1 byte, là tổng của 128 byte dữ liệu modulo 256. Bên nhận xác nhận từng block hoặc yêu cầu gửi lại block đó. Lý do thiết kế như vậy là vấn đề chi phí. Trên đường dial-up, bạn trả tiền theo thời gian, nên lỗi đường truyền chỉ nên làm mất một block thay vì toàn bộ lần truyền.
Điểm yếu nằm ngay trong mô tả đó. XMODEM chờ acknowledgement sau mỗi 128 byte. Chuck Forsberg viết rõ trong đặc tả ZMODEM: "Độ dài block ngắn làm throughput giảm khi dùng với các hệ thống timesharing, packet-switched network và mạch vệ tinh." Latency mới là thứ làm stop-and-wait hoạt động kém, không phải bandwidth. Mỗi round trip tạo ra một khoảng im lặng trên đường truyền mà bạn vẫn đang bị tính phí.
YMODEM xuất hiện tiếp theo, và Ward Christensen đặt tên này vào năm 1985. Đóng góp của nó là batch transfer. Bên gửi khai báo filename và kích thước trước phần dữ liệu, nên nhiều file có thể được truyền trong một session và bên nhận biết điểm kết thúc của từng file.
ZMODEM là câu trả lời của Chuck Forsberg, được viết tại Omen Technology. Đặc tả có revision ngày 14 October 1988 và nêu rằng "ZMODEM được phát triển cho public domain theo một hợp đồng với Telenet". Telenet vận hành một packet-switched data network công cộng, và hợp đồng đó thể hiện trong thiết kế. ZMODEM escape các network control character để packet network ở giữa không tiêu thụ chúng. Nó đánh dấu điểm bắt đầu của mỗi frame bằng một chuỗi ký tự duy nhất thay vì suy ra ranh giới frame từ sự im lặng, nhờ đó có thể phục hồi sau nhiễu mà không phải chờ hết timeout. Nó cũng có cơ chế resume tường minh, nên một lần truyền bị gián đoạn có thể tiếp tục từ vị trí đã dừng.
Quan trọng nhất, nó không còn phải chờ. Đặc tả tự mô tả rằng "ZMODEM về cơ bản dùng toàn bộ file làm một window". Bên gửi truyền liên tục và chỉ dừng khi bên nhận báo có lỗi. Đó cũng là insight mà TCP mã hóa trong window của mình, nhưng được tiếp cận từ hướng ngược lại, bởi một người quan sát modem nằm im.
Vì sao hai kết nối của FTP nhanh chóng trở nên lỗi thời
FTP ra đời trước tất cả các giao thức đó. RFC 114, “A File Transfer Protocol”, có ngày 16 April 1971 và do A. Bhushan viết.
Điểm đáng chú ý là RFC 114 đã xem xét thiết kế hai kết nối rồi bác bỏ nó. Bhushan cân nhắc “sử dụng hai liên kết full-duplex, một liên kết cho thông tin điều khiển và một liên kết cho dữ liệu”, sau đó kết luận: “Chúng tôi khuyến nghị sử dụng một kết nối full-duplex duy nhất để trao đổi cả dữ liệu lẫn thông tin điều khiển.” Việc tách hai kết nối xuất hiện sau đó. RFC 354, ngày 8 July 1972, nêu rằng “dữ liệu và file chỉ được truyền qua kết nối dữ liệu”, còn các lệnh đi qua một kết nối Telnet riêng. RFC 959, tháng October 1985, do Postel và Reynolds viết, là phiên bản mà mọi người vẫn triển khai.
RFC 959 cũng cố định các port. Port dữ liệu mặc định của server là “port liền kề với port của kết nối điều khiển (tức là L-1)”, nghĩa là port 20 khi kết nối điều khiển dùng port 21.
Đây là phần không tồn tại lâu dài. Ở chế độ ban đầu của FTP, server mở kết nối dữ liệu ngược về client. Client phía sau NAT (network address translation) không có địa chỉ mà server có thể kết nối tới. Client phía sau firewall cũng không chấp nhận kết nối đến. Vì vậy, kết nối dữ liệu không bao giờ đến nơi và việc truyền bị treo ngay khi client yêu cầu listing hoặc file. Giải pháp là PASV. RFC 959 định nghĩa PASV là yêu cầu server “’listen’ trên một port dữ liệu (không phải port dữ liệu mặc định) và chờ kết nối thay vì tự khởi tạo kết nối khi nhận lệnh truyền”. Server trả về địa chỉ và port để client kết nối:
PASV
227 Entering Passive Mode (203,0,113,10,195,80)Phản hồi đó có nghĩa là host 203.0.113.10, port bằng 195 nhân 256 cộng 80, tức 50000. Đọc lại một lần nữa, bạn sẽ thấy vấn đề mang tính cấu trúc. Endpoint của kết nối thứ hai được thông báo bên trong payload của kết nối thứ nhất. NAT hoặc firewall không thể chuyển tiếp kết nối đó nếu không phân tích control channel và mở port được chỉ ra trong đó. Linux có sẵn một connection tracking helper thực hiện đúng việc này. Helper chỉ hoạt động khi control connection còn ở dạng cleartext. Vì vậy, khi bọc FTP trong TLS (transport layer security), middlebox đã giúp FTP hoạt động sẽ không còn đọc được nội dung cần thiết.
Đó là bài học của FTP trong một câu. FTP biến network thành một thành phần tham gia vào protocol. Một protocol cần network hiểu nó sẽ không thể tồn tại khi network ngừng tin tưởng protocol đó.
Kết cục đã được ghi nhận. Firefox loại bỏ hỗ trợ FTP trong version 90 vào July 2021. Chrome loại bỏ code FTP trong Chrome 95 vào October 2021.
rcp và các lệnh r: tin cậy theo hostname
4.2BSD, được Berkeley phát hành vào năm 1983 với nguồn tài trợ của DARPA, đã giới thiệu rcp, rsh và rlogin. Chúng được xây dựng cho một campus gồm các máy Unix trên cùng một mạng, và mô hình xác thực thể hiện rõ điều đó. Một host xác nhận user nào đang thực hiện lệnh. Nếu /etc/hosts.equiv hoặc ~/.rhosts của user cho biết host đó được tin cậy, xác nhận này được chấp nhận và không yêu cầu password.
Cần mô tả thẳng cơ chế này, vì đó là lý do các lệnh này biến mất. Cơ chế tin cậy dựa trên một địa chỉ và một xác nhận. Cả hai đều được truyền dưới dạng cleartext trên mạng, nên bất kỳ ai trên đường truyền cũng có thể đọc và giả mạo chúng. Mô hình này phù hợp với môi trường được mô tả trong quá trình từ Unix đến Linux, khi mạng chỉ là một tòa nhà. Nó không còn phù hợp ngay khi mạng trở thành internet.
Điểm rcp làm đúng là interface. Nguồn, đích, hoàn tất. Không cần mở session, thương lượng transfer mode hoặc thiết lập kết nối thứ hai. Nó hoạt động giống cp với dấu hai chấm trong path. Interface này vẫn tồn tại lâu hơn protocol của nó bốn thập kỷ.
SSH bao trùm toàn bộ nhóm công cụ này
Năm 1995, Tatu Ylonen, khi đó là nhà nghiên cứu tại Helsinki University of Technology, đã viết SSH để đáp lại một cuộc tấn công sniffing mật khẩu trên mạng của trường. Ông phát hành SSH dưới dạng free software kèm source code vào tháng 7 năm 1995. Đến cuối năm đó, ước tính có khoảng 20,000 người dùng tại 50 quốc gia. Tháng 12 năm 1995, ông thành lập SSH Communications Security để tiếp tục phát triển SSH.
Giấy phép trở nên chặt chẽ hơn trong các phiên bản sau, nên các developer của OpenBSD đã fork bản phát hành cuối cùng vẫn còn giấy phép tự do, ssh 1.2.12. Bản import ban đầu được thực hiện vào ngày 26 tháng 9 năm 1999. OpenSSH 1.2.2 được phát hành cùng OpenBSD 2.6 vào ngày 1 tháng 12 năm 1999. Bản fork này là một ví dụ ngắn gọn cho lý do điều khoản cấp phép open source quan trọng trong thực tế, vì implementation SSH mà gần như mọi người đang chạy hiện nay bắt nguồn từ phiên bản duy nhất còn có giấy phép cho phép điều đó.
Khi SSH xuất hiện, việc truyền file không còn là một vấn đề riêng. Một stream được xác thực và mã hóa, có thể mang nhiều channel, đã cung cấp sẵn những chức năng mà các protocol cũ phải tự xây dựng: tính toàn vẹn, thứ tự dữ liệu và một đường truyền dữ liệu thứ hai không cần mở thêm kết nối TCP. Nếu các cơ chế này còn mới với bạn, hãy bắt đầu từ việc SSH thực sự là gì trước khi đi tiếp.
Từ đó có 2 công cụ. scp là wire protocol của rcp chạy bên trong một phiên SSH, nên nó kế thừa nguyên vẹn command line của rcp. SFTP là một thiết kế khác: một file protocol thực sự, có directory listing, file attributes và random access, được truyền trên một SSH channel. SFTP chưa bao giờ trở thành RFC. IETF draft draft-ietf-secsh-filexfer đạt version 13 vào ngày 18 tháng 7 năm 2006 rồi hết hạn. OpenSSH triển khai version 3 của draft đó. Secure file transfer protocol được sử dụng rộng rãi nhất thế giới là một revision được đánh số của một draft đã bị bỏ dở, nhưng nó vẫn hoạt động.
Legacy scp protocol hiện cũng đã bị loại bỏ. OpenSSH 8.8, phát hành ngày 26 tháng 9 năm 2021, cảnh báo rằng “một bản phát hành OpenSSH trong tương lai gần sẽ chuyển scp(1) từ legacy scp/rcp protocol sang dùng SFTP mặc định”. OpenSSH 9.0, phát hành ngày 8 tháng 4 năm 2022, đã thực hiện thay đổi đó: “Bản phát hành này chuyển scp(1) từ legacy scp/rcp protocol sang dùng SFTP protocol mặc định.”
Lý do của thay đổi này giải thích một phần folklore. Legacy scp protocol mở rộng wildcard của remote filename bằng cách chuyển chúng cho remote shell. Vì vậy, người dùng được hướng dẫn đặt mọi metacharacter trong remote path bên trong dấu ngoặc kép kép. Ghi chú của bản 8.8 cho biết scp chạy trên SFTP “không còn yêu cầu cách quoting khó chịu và dễ lỗi này”. Vì vậy, trên một server hiện tại, scp là một SFTP client sử dụng command line của rcp. Interface từ năm 1983 vẫn tồn tại. Wire protocol từ năm 1983 thì không.
rsync, 1996: gửi phần khác biệt thay vì gửi cả file
Andrew Tridgell và Paul Mackerras công bố rsync vào ngày 19 June 1996 tại Australian National University, cùng với báo cáo kỹ thuật TR-CS-96-05, "The rsync algorithm".
Mọi protocol trước rsync đều tìm cách truyền một file mà không làm hỏng file đó. rsync đặt câu hỏi: phía bên kia đã có bao nhiêu phần của file này? Báo cáo mô tả mục tiêu là "a low-bandwidth high-latency bi-directional communications link", và mục tiêu cụ thể là xác định "parts of the source file which are identical to some part of the destination file", để chỉ gửi những phần không khớp.
Cơ chế này đáng để tìm hiểu vì nó giải thích cách rsync hoạt động. Receiver chia bản sao hiện có thành các block có kích thước cố định và tính 2 checksum cho mỗi block: một checksum yếu, tính nhanh; một checksum mạnh, tính tốn nhiều hơn. Receiver gửi danh sách đó cho sender. Sender trượt một cửa sổ qua file của mình, mỗi lần dịch 1 byte, đồng thời cập nhật checksum yếu theo cách incremental. Nhờ vậy, việc quét từng byte mới đủ nhanh để thực hiện. Sau đó, rsync xác nhận kết quả khớp yếu bằng checksum mạnh. Các kết quả khớp đã xác nhận trở thành tham chiếu đến block. Mọi phần còn lại được gửi dưới dạng byte literal. Receiver dựng lại file từ các tham chiếu đến những block đã có và các byte literal vừa nhận.
Nếu chèn 1 byte vào đầu một file lớn, công cụ tính khác biệt đơn giản phải gửi cả file vì mọi offset đều đã thay đổi. Cửa sổ rolling tìm thấy các block giống nhau tại những offset mới, nên rsync chỉ gửi 1 byte cùng phần bookkeeping. Đây là lý do rsync vẫn là công cụ phù hợp cho một directory mà bạn sẽ copy nhiều hơn 1 lần.
Có 2 hành vi thường khiến người dùng bất ngờ, và cả 2 đều được nêu trong manual. Thứ nhất, rsync không checksum file để quyết định có kiểm tra file hay không. rsync "finds files that need to be transferred using a 'quick check' algorithm (by default) that looks for files that have changed in size or in last-modified time". Nếu nội dung file thay đổi nhưng size và timestamp không đổi, rsync sẽ bỏ qua file đó. --checksum thay đổi hành vi này và buộc cả 2 phía đọc toàn bộ mọi file cần kiểm tra. Thứ hai, delta algorithm mặc định bị tắt khi cả 2 path đều là local, vì đọc và checksum 2 bản copy trên cùng một máy tốn nhiều tài nguyên hơn so với copy trực tiếp các byte. Lợi ích của delta algorithm chỉ xuất hiện khi link là phần chậm nhất.
Những công cụ bạn thực sự dùng trên VPS và lý do
Tóm lại: dùng SFTP cho vài file; dùng rsync qua SSH cho một thư mục mà bạn sẽ sao chép lại.
Cả hai đều chạy qua SSH, nên mặc định đều có xác minh host key và mã hóa mà không cần cấu hình thêm. Đây là 50 năm công sức được tích hợp vào một cấu hình mặc định. Nhà thiết kế Kermit phải giả định rằng đường truyền có thể làm hỏng dữ liệu, nên họ tích hợp checksum và truyền lại vào protocol. Hiện nay TCP đảm nhiệm việc đó. Christensen và Forsberg phải giả định rằng mỗi byte đều tốn tiền, nên họ tích hợp khả năng tiếp tục truyền và streaming. Hiện nay thuật toán delta của rsync đảm nhiệm việc đó và làm tốt hơn. Tác giả của FTP giả định rằng mạng gồm các host phối hợp với nhau, và đó là giả định duy nhất trong số này hóa ra sai theo cách mà không lượng công sức nào dành cho protocol cũng có thể khắc phục.
Checksum còn có tác dụng gì
Từ “checksum” đã đảm nhiệm ba vai trò khác nhau trong lịch sử này, và chúng không thể thay thế cho nhau.
Checksum trên từng packet của Kermit và XMODEM phát hiện dữ liệu bị hỏng khi truyền qua đường truyền. Ngày nay, TCP checksum và cơ chế sửa lỗi ở tầng liên kết đã xử lý việc đó. Vì vậy, không có công cụ truyền file hiện đại nào yêu cầu bạn phải quan tâm đến vấn đề này.
Checksum theo block của rsync không trả lời câu hỏi “dữ liệu này có chính xác không”. Nó trả lời câu hỏi “bạn đã có block này chưa”. Trong trường hợp đó, checksum mạnh là một khóa tra cứu, không phải bằng chứng về nguồn gốc của file.
Vai trò thứ ba vẫn do bạn đảm nhiệm. Checksum được công bố cùng file release trả lời một câu hỏi mà TLS không thể trả lời. TLS chứng minh rằng bạn đã kết nối đến đúng server. Nó không chứng minh file đúng đang nằm trên server đó, và cũng không bảo vệ file bạn tải từ một mirror. Vì vậy, checksum và chữ ký của release vẫn đáng để dành 30 giây kiểm tra. Bạn cũng dễ hình thành thói quen này: kiểm tra checksum của mọi file tải xuống trước khi cài đặt.
Mọi vấn đề khác trong câu chuyện này đều đã được giải quyết bởi tầng bên dưới. Riêng vấn đề đó thì chưa, vì ngay từ đầu nó không phải là vấn đề mạng.
FAQ
FTP còn an toàn để dùng trên VPS không?
Không. FTP thuần gửi thông tin xác thực và nội dung file dưới dạng plaintext, nên bất kỳ ai trên đường truyền cũng có thể đọc cả hai. FTP cũng phụ thuộc vào firewall có khả năng phân tích control channel, nhưng điều này không còn khả thi ngay khi bạn mã hóa control channel bằng TLS. Các trình duyệt đã loại bỏ FTP: Firefox xóa hỗ trợ FTP trong version 90 vào tháng 7 năm 2021, còn Chrome xóa code này trong version 95 vào tháng 10 năm 2021. Hãy dùng SFTP qua SSH. Cách này chỉ cần một port và không cần middlebox hiểu protocol.
Tại sao FTP lại cần passive mode?
Vì trong mode nguyên bản của FTP, server mở data connection ngược về client. RFC 959 đặt data port mặc định của server tại "port liền kề với control connection port (tức là L-1)", nên đó là port 20 khi control port là port 21. Client phía sau NAT (network address translation) không có địa chỉ mà server có thể kết nối tới, nên connection đó không bao giờ đến nơi và quá trình truyền bị treo. PASV đảo ngược hướng kết nối: server chuyển sang listening, rồi trả về địa chỉ và port trong một 227 Entering Passive Mode reply để client kết nối tới.
scp còn dùng protocol riêng không?
Không, kể từ OpenSSH 9.0, được release vào ngày 8 tháng 4 năm 2022. Bản này "chuyển scp(1) từ protocol scp/rcp legacy sang dùng SFTP protocol theo mặc định". OpenSSH 8.8 đã thông báo thay đổi này vào tháng 9 năm 2021. Khác biệt dễ thấy nằm ở cách quoting. Protocol cũ mở rộng wildcard từ xa bằng cách truyền chúng cho remote shell, còn protocol dựa trên SFTP thì không làm vậy. Vì thế, các path phụ thuộc vào việc shell mở rộng sẽ hoạt động khác trước.
Khi nào rsync phù hợp hơn scp trên VPS?
Khi bạn sẽ copy cùng một tree nhiều hơn một lần. rsync chỉ gửi những phần của mỗi file mà destination chưa có, nên lần copy thứ hai rẻ hơn nhiều so với lần đầu. Với một file duy nhất mà destination chưa từng nhận, scp và rsync truyền số byte gần tương đương, còn scp đơn giản hơn. Lưu ý rằng mặc định rsync quyết định cần kiểm tra file nào dựa trên kích thước và thời gian sửa đổi. Vì vậy, một file đã thay đổi nội dung nhưng kích thước và timestamp không đổi cần --checksum trước khi rsync nhận ra thay đổi đó.
Tại sao Kermit lại encode file thành text có thể in được thay vì gửi raw byte?
Vì connection mà Kermit nhắm tới là một terminal line nối vào mainframe, không phải byte pipe. Những đường truyền đó có thể chỉ hỗ trợ 7-bit, còn terminal driver của mainframe xử lý control character thay vì chuyển tiếp chúng. Kermit encode control byte và byte có high bit thành các ký tự có thể in được để không thành phần nào trên đường truyền phản ứng với chúng. Cách encoding này làm file binary lớn hơn khi truyền, nhưng đó là đánh đổi phù hợp để tránh file bị hỏng khi nhận.