Trong các hạ tầng mạng riêng ảo quan trọng, tính sẵn sàng liên tục luôn là yêu cầu cốt lõi. Các cổng chuyển tiếp doanh nghiệp, proxy dự phòng WireGuard qua TCP và trạm chuyển tiếp lưu lượng định tuyến đồng thời hàng chục nghìn phiên TCP của người dùng. Khi các kỹ sư phát hành bản vá bảo mật khẩn cấp, sửa lỗi rò rỉ bộ nhớ hoặc nâng cấp kiến trúc, đội ngũ vận hành đối mặt với một thách thức nan giải: khởi động lại tiến trình daemon sẽ ngắt toàn bộ đường truyền đang hoạt động.
Theo vòng đời socket thông thường trong nhân Linux, khi một tiến trình gọi close() hoặc bị dừng, nhân mạng sẽ lập tức gửi gói tin FIN hoặc RST đến đầu xa. Đối với người dùng VPN, việc ngắt đột ngột này khiến đường truyền sụp đổ, truyền tải tệp bị hỏng, hội nghị video bị ngắt và kích hoạt hàng loạt yêu cầu xác thực lại. Hiện tượng hàng nghìn máy trạm kết nối đồng thời tạo ra hiệu ứng tháp lũ (thundering herd), làm nghẽn máy chủ xác thực và quá tải tài nguyên CPU.
Giải pháp truyền thống là tiêu thoát kết nối (connection draining), tức chuyển lưu lượng mới sang tiến trình mới và giữ tiến trình cũ chạy cho đến khi các phiên cũ tự ngắt. Tuy nhiên, các đường hầm VPN có vòng đời rất dài và hiếm khi tự đóng. Tại các cổng biên thực tế, quá trình tiêu thoát có thể kéo dài nhiều giờ hoặc nhiều ngày, cản trở việc triển khai các bản vá lỗ hổng nghiêm trọng. Lời giải triệt để cho bài toán này là chuyển giao trực tiếp socket đang hoạt động giữa hai tiến trình.
Bài toán ngắt kết nối: Cập nhật daemon và gián đoạn phiên VPN
Sự nhạy cảm của các kết nối truyền tải khi nâng cấp dịch vụ xuất phát từ bản chất duy trì trạng thái của giao thức TCP. Khác với cơ chế chuyển tiếp UDP phi trạng thái, mỗi socket TCP đang hoạt động lưu giữ một tập hợp thông số phức tạp bên trong nhân mạng Linux:
- Bộ đếm cửa sổ trượt: Các số thứ tự tuần tự (
snd_una,snd_nxt,rcv_nxt) dùng để điều phối việc phân phối luồng byte đáng tin cậy. - Ước lượng động: Thời gian truyền khứ hồi trung bình (
srtt), phương sai trễ (rttvar) và tham số cửa sổ tắc nghẽn (snd_cwnd,snd_ssthresh). - Bộ đệm dữ liệu đang truyền: Các cấu trúc
sk_buffchứa dữ liệu đi đã gửi nhưng chờ xác nhận, cùng dữ liệu đến đang chờ ứng dụng đọc.
Tác động khi khởi động lại tiến trình theo cách truyền thống:
[ Ứng dụng người dùng ] ──► [ Đường hầm VPN ] ──► [ Daemon cũ (PID 101) ]
│
(Nhận lệnh dừng)
│
▼
[ Ứng dụng người dùng ] ◄── [ Nhận gói TCP RST ] ◄── [ Nhân giải phóng socket ]
│
(Mất kết nối đột ngột)
│
▼
[ Cơn bão kết nối lại: Hàng nghìn phiên bắt tay làm quá tải tiến trình mới ]
Khi máy chủ biên dừng tiến trình cũ mà không di chuyển trạng thái, ngăn xếp mạng của nhân sẽ ngay lập tức dọn dẹp các cấu trúc socket liên quan. Nhân gửi cờ Reset (RST) tới toàn bộ máy trạm, phá vỡ đường truyền bảo mật. Đối với người dùng từ xa và luồng công việc tự động, điều này đồng nghĩa với việc mất kết nối và gián đoạn hoạt động.
Kiến trúc Linux TCP_REPAIR: Cơ chế đóng băng socket
Nhằm hỗ trợ việc lưu ảnh và phục hồi tiến trình trong container (CRIU), nhân Linux cung cấp tùy chọn socket TCP_REPAIR thuộc tầng SOL_TCP. Tính năng này cho phép một tiến trình có thẩm quyền đưa socket TCP đang hoạt động vào trạng thái ngưng đọng có kiểm soát.
Trong điều kiện tiêu chuẩn, nhân cấm tầng không gian người dùng can thiệp trực tiếp vào số thứ tự gói tin hay bộ đếm thời gian để ngăn ngừa tấn công mạng và vi phạm giao thức. Tuy nhiên, khi kích hoạt TCP_REPAIR, nhân tạm thời nới lỏng cơ chế kiểm soát nghiêm ngặt, cho phép phần mềm giám sát đọc và điều chỉnh các biến trạng thái nội bộ.
Vòng đời socket TCP trong quá trình di chuyển bằng chế độ sửa chữa:
[ Hoạt động bình thường ] ──► setsockopt(fd, SOL_TCP, TCP_REPAIR, TCP_REPAIR_ON)
│
▼
[ CHẾ ĐỘ SỬA CHỮA ]
│
┌───────────────────────────┴───────────────────────────┐
▼ ▼
Đọc / ghi số thứ tự gói Đóng băng bộ đếm (RTO, Keepalive)
Trích xuất bộ đệm đến / đi Ngăn nhân tự động gửi gói tin RST
│ │
└───────────────────────────┬───────────────────────────┘
│
▼
[ Tiến trình mới nhận FD ] ──► setsockopt(fd, SOL_TCP, TCP_REPAIR, TCP_REPAIR_OFF)
│
▼
[ Tái kích hoạt kết nối ]
1. Đóng băng bộ đếm thời gian và kích hoạt trạng thái sửa chữa
Việc chuyển socket sang chế độ sửa chữa đòi hỏi quyền quản trị mạng (CAP_NET_ADMIN). Tiến trình giám sát khởi động quá trình tạm ngưng thông qua lệnh setsockopt():
int repair_mode = 1;
if (setsockopt(sock_fd, SOL_TCP, TCP_REPAIR, &repair_mode, sizeof(repair_mode)) < 0) {
perror("Lỗi kích hoạt chế độ TCP_REPAIR");
return -1;
}
Khi chế độ này có hiệu lực, nhân lập tức dừng mọi bộ đếm thời gian bên trong socket. Đồng hồ tính thời gian chờ truyền lại (RTO) ngừng đếm, các gói thăm dò duy trì liên lạc (Keepalive) dừng phát và bộ đếm cửa sổ rỗng bị đóng băng. Nếu có gói tin từ máy trạm gửi đến trong lúc socket bị ngưng đọng, nhân giữ chúng trong hàng đợi của trình điều khiển mà không phát sinh gói tin từ chối RST.
2. Điểm kiểm tra và phục hồi hàng đợi cùng số thứ tự TCP
Ở chế độ sửa chữa, phần mềm vận hành có thể đọc và hiệu chỉnh chính xác vị trí số thứ tự của cả luồng dữ liệu đến lẫn đi thông qua lệnh TCP_REPAIR_QUEUE và TCP_QUEUE_SEQ:
uint32_t current_seq;
socklen_t seq_len = sizeof(current_seq);
int queue_target = TCP_SEND_QUEUE;
/* Chọn hàng đợi gửi đi để kiểm tra số thứ tự hiện tại */
setsockopt(sock_fd, SOL_TCP, TCP_REPAIR_QUEUE, &queue_target, sizeof(queue_target));
getsockopt(sock_fd, SOL_TCP, TCP_QUEUE_SEQ, ¤t_seq, &seq_len);
Giao diện này phục vụ hai mục đích thiết yếu:
- Lưu trữ trạng thái: Ghi nhận chính xác số byte đã được đầu xa xác nhận.
- Tái lập trạng thái: Trong trường hợp tạo lại socket trong một không gian tên mạng độc lập, tiến trình tiếp nhận có thể ghi lại số thứ tự vào socket mới trước khi kết nối trở lại.
Cơ chế chuyển giao socket: SCM_RIGHTS so với CRIU
Để triển khai giải pháp chuyển tiếp VPN không gián đoạn, việc chuyển giao bộ mô tả tệp (file descriptor) giữa tiến trình cũ và tiến trình kế thừa có thể thực hiện theo hai mô hình kỹ thuật chính.
Kiến trúc bàn giao socket giữa hai tiến trình:
[ Tiến trình cũ (Phiên bản v1) ]
│ 1. setsockopt(TCP_REPAIR, TCP_REPAIR_ON)
│ 2. Đóng gói ngữ cảnh mã hóa và trạng thái số thứ tự
│ 3. Gửi bộ mô tả tệp qua sendmsg() với SCM_RIGHTS
▼
[ Giao tiếp liên tiến trình qua UNIX Domain Socket ]
│
▼ 4. Nhận bộ mô tả tệp bằng recvmsg()
[ Tiến trình mới (Phiên bản v2) ]
│ 5. Xác thực số thứ tự hàng đợi và đăng ký epoll
│ 6. setsockopt(TCP_REPAIR, TCP_REPAIR_OFF)
▼
[ Tiếp tục chuyển tiếp lưu lượng liền mạch ]
1. Truyền bộ mô tả tệp liên tiến trình qua UNIX Domain Socket
Khi thực hiện nâng cấp phần mềm trực tiếp trên cùng một máy chủ, việc chuyển giao bộ mô tả tệp qua UNIX Domain Socket bằng thông điệp phụ trợ SCM_RIGHTS là phương án đạt hiệu năng cao và độ trễ thấp. Thay vì phải tuần tự hóa dữ liệu và tái tạo socket, hệ điều hành chia sẻ trực tiếp con trỏ cấu trúc tệp bên trong bảng mô tả của nhân.
Tiến trình cũ tạo một cấu trúc struct msghdr chứa cờ điều khiển SCM_RIGHTS cùng số nguyên mô tả tệp. Tiến trình mới tiếp nhận qua hàm recvmsg(), nhận về một bộ mô tả hợp lệ trỏ tới chính xác cấu trúc socket trong nhân mà không phải sao chép bộ nhớ.
2. Quy trình phục hồi trạng thái và thoát chế độ sửa chữa
Sau khi tiếp nhận thành công bộ mô tả socket, tiến trình mới đồng bộ ngữ cảnh mã hóa, gắn socket vào vòng lặp sự kiện bất đồng bộ (epoll hoặc io_uring), rồi đưa socket ra khỏi chế độ sửa chữa:
int repair_disable = 0;
if (setsockopt(imported_fd, SOL_TCP, TCP_REPAIR, &repair_disable, sizeof(repair_disable)) < 0) {
perror("Lỗi tắt chế độ TCP_REPAIR");
return -1;
}
Ngay khi lệnh tắt có hiệu lực, nhân mạng tính toán lại hạn định của các bộ đếm thời gian theo mốc thời gian thực và giải phóng hàng đợi gói tin. Luồng dữ liệu đi tiếp tục được phát qua giao diện mạng vật lý và dữ liệu đến được chuyển trực tiếp vào tiến trình mới mà không rơi rụng một byte nào.
Kịch bản vận hành: Triển khai di chuyển socket không mất gói
Quy trình nâng cấp không gián đoạn tại các cụm máy chủ chuyển tiếp tuân theo bốn giai đoạn kiểm soát chặt chẽ:
- Khởi động và kiểm tra: Tiến trình mới được khởi tạo song song với tiến trình cũ, nạp tệp cấu hình, khóa mật mã và kiểm tra sẵn sàng trước khi can thiệp vào các phiên kết nối.
- Đóng băng có kiểm soát: Đưa các socket khách hàng vào trạng thái
TCP_REPAIR_ONtheo từng nhóm nhỏ định mức để đảm bảo hệ thống phản hồi ổn định. - Bàn giao qua IPC: Truyền tải các bộ mô tả tệp cùng thông tin phiên bảo mật qua kênh UNIX domain socket cục bộ.
- Mở băng và hoàn tất: Gọi
TCP_REPAIR_OFFtrên tiến trình mới, kích hoạt vòng lặp xử lý sự kiện và phát tín hiệu kết thúc an toàn cho tiến trình cũ.
Trình tự thời gian bàn giao trạm chuyển tiếp không gián đoạn:
Tiến trình cũ Trạng thái TCP trong nhân Tiến trình mới
│ │ │
├─ TCP_REPAIR_ON ──────────► │ (Đóng băng bộ đếm) │
│ │ │
├─ SCM_RIGHTS fd ──────────────────────────────────────► │ (Nhận mô tả tệp)
│ │ │
│ │ ◄── TCP_REPAIR_OFF ───────┤ (Khôi phục bộ đếm)
│ │ │
├─ (Dừng an toàn) │ (Chuyển tiếp tốc độ cao) ├─ (Xử lý lưu lượng)
Đánh đổi độ sẵn sàng cao và giảm thiểu rủi ro
Việc ứng dụng kỹ thuật di chuyển socket bằng TCP_REPAIR đòi hỏi xem xét kỹ các yếu tố kỹ thuật sau:
- Phân quyền bảo mật: Thao tác trên cờ sửa chữa yêu cầu đặc quyền
CAP_NET_ADMIN. Ứng dụng cần áp dụng nguyên tắc tối thiểu quyền, thu hồi đặc quyền này ngay sau khi hoàn tất quy trình di chuyển. - Giới hạn thời gian truyền lại của máy trạm: Dù bộ đếm phía máy chủ tạm dừng, đồng hồ truyền lại của máy khách vẫn tiếp tục chạy. Toàn bộ chu trình bàn giao cần diễn ra trong khoảng 200 đến 500 mili giây để tránh kích hoạt cơ chế hủy kết nối do quá hạn RTO từ phía máy khách.
- Đồng bộ mã hóa tầng ứng dụng: Bảo tồn luồng byte TCP là chưa đủ nếu ngữ cảnh bảo mật tầng trên bị mất. Khóa mã hóa TLS và phiên làm việc WireGuard qua TCP phải được đóng gói và truyền tải đồng bộ cùng bộ mô tả socket.
Kiến trúc RiceGuard: Chuyển tiếp liền mạch và duy trì phiên kết nối
VPNRice giải quyết bài toán duy trì liên lạc dịch vụ biên thông qua tích hợp kiến trúc sâu trong lõi mạng RiceGuard. Thay vì buộc người dùng doanh nghiệp và các luồng truyền tải dung lượng cao phải kết nối lại mỗi khi hệ thống cập nhật phần mềm, RiceGuard ứng dụng cơ chế di chuyển socket tự động ở tầng nhân.
Bằng cách kết hợp bộ định tuyến socket eBPF với tính năng TCP_REPAIR của Linux, các trạm chuyển tiếp RiceGuard di chuyển trơn tru các đường truyền đang chạy giữa các luồng xử lý độc lập mà không gây mất gói hay phát sinh cờ ngắt TCP. Các phiên làm việc của người dùng luôn được duy trì thông suốt, mang lại độ tin cậy vượt bậc và bảo vệ quyền riêng tư số an toàn trên toàn cầu.



