Các gateway VPN quy mô lớn thường duy trì các cổng lắng nghe TCP song song với các đường hầm UDP. Trong môi trường hạ tầng thực tế, TCP đóng vai trò làm kênh truyền dự phòng khi mạng doanh nghiệp hạn chế lưu lượng UDP, đồng thời phục vụ mặt phẳng điều khiển, đường truyền mã hóa TLS và các giao diện quản trị. Khi các node công khai mở cổng TCP 443 ra Internet, nguy cơ đối mặt với các đợt tấn công từ chối dịch vụ phân tán dạng TCP SYN flood là điều không thể tránh khỏi.
Dù các dòng card mạng hiện đại xử lý hàng triệu gói tin mỗi giây, kiến trúc theo dõi kết nối truyền thống của Linux lại dễ sụp đổ trước các đợt bão kết nối giả mạo. Nếu hệ thống ghi nhận trạng thái cho mọi gói tin gửi tới trước khi xác minh danh tính máy khách, bảng trạng thái nội bộ sẽ tràn trước khi băng thông mạng bị nghẽn. Giải pháp triệt để cho vấn đề này là loại bỏ hoàn toàn việc lưu trạng thái trong giai đoạn bắt tay ban đầu bằng công nghệ Linux nftables SYNPROXY.
Việc nắm vững cơ chế vận hành của SYNPROXY đòi hỏi phân tích chi tiết quy trình xử lý gói tin của hệ thống Netfilter trên nhân Linux.
Mối đe dọa làm cạn kiệt bảng theo dõi kết nối:
Lưu lượng SYN Flood ──> Card mạng Ingress ──> Netfilter PREROUTING ──> Cấp phát bộ nhớ conntrack (struct nf_conn)
│
TRÀN BẢNG TRẠNG THÁI (nf_conntrack: table full)
│
MẤT KẾT NỐI (Toàn bộ người dùng bị rớt)
─────────────────────────────────────────────────────────────────────────────────────────────────────────────
Cơ chế lọc phi trạng thái với nftables SYNPROXY:
Lưu lượng SYN Flood ──> PREROUTING (notrack) ──> INPUT (SYNPROXY) ──> Phản hồi SYN-ACK phi trạng thái (Syncookie)
│
(Không tốn RAM / Không tạo trạng thái)
│
Máy khách hợp lệ gửi ACK ──────────────────────────────────────> Khớp Syncookie ──> Khởi tạo conntrack ──> VPN Daemon
Điểm nghẽn conntrack: Giới hạn của syncookie tầng socket
Nhiều quản trị viên hệ thống cho rằng việc bật tính năng syncookie qua tham số net.ipv4.tcp_syncookies = 1 là đủ để ngăn chặn triệt để tấn công SYN flood. Thực tế, cơ chế syncookie của hệ điều hành chỉ bảo vệ hàng đợi lắng nghe của socket tầng ứng dụng (listen(backlog)), chứ không bảo vệ được phân hệ theo dõi kết nối của Netfilter (nf_conntrack).
Trong luồng xử lý mạng mặc định của Linux, Netfilter can thiệp vào gói tin ngay tại hook NF_INET_PRE_ROUTING, nằm trước ngăn xếp giao vận cục bộ (NF_INET_LOCAL_IN). Khi một gói TCP gắn cờ SYN đi vào máy chủ, nf_conntrack lập tức cấp phát cấu trúc dữ liệu struct nf_conn và ghi vào bảng băm toàn cục ở trạng thái SYN_RECV:
Gói tin đi vào ──> nf_conntrack_in() ──> init_conntrack() ──> kmem_cache_alloc(nf_conntrack_cachep)
Mỗi bản ghi tiêu tốn khoảng 320 đến 384 byte bộ nhớ slab nhân Linux. Với cấu hình mặc định nf_conntrack_max khoảng 262.144 mục, kẻ tấn công chỉ cần bơm 300.000 gói SYN giả mạo mỗi giây là có thể lấp đầy bảng trạng thái trong chưa đầy 900 mili giây.
Hậu quả khi bảng conntrack bị tràn:
- Nhân Linux phát cảnh báo lỗi
net_ratelimit: nf_conntrack: table full, dropping packet. - Toàn bộ các kết nối VPN đang hoạt động và các phiên bắt tay mới hợp lệ đều bị loại bỏ ngay lập tức.
- Tải CPU tăng vọt do các luồng ngắt mềm (softirq) phải liên tục quét các thùng băm đã đầy.
Do syncookie tầng socket nằm trong hàm tcp_v4_rcv()—sau khi nf_conntrack đã thất bại trong việc cấp phát bộ nhớ—chúng hoàn toàn không có cơ hội kích hoạt. Muốn bảo vệ gateway, việc kiểm tra bắt tay phải được đưa lên trước tầng theo dõi kết nối.
Kiến trúc nội tại của Netfilter SYNPROXY
Cơ chế synproxy được triển khai trực tiếp trong nhân Linux tại tệp mã nguồn net/netfilter/nf_synproxy_core.c và được tích hợp qua công cụ tường lửa nftables. Hệ thống hoạt động như một proxy TCP phi trạng thái ở tầng nhân, tách quy trình kết nối thành hai giai đoạn độc lập: bắt tay ngoài không lưu trạng thái với máy khách, sau đó bắt tay trong với tiến trình ứng dụng cục bộ.
Máy khách bên ngoài nftables SYNPROXY Tiến trình VPN cục bộ
│ │ │
│─── 1. TCP SYN [MSS, WScale, SACK] ─────>│ (Phi trạng thái, không cấp phát RAM) │
│ │ │
│<── 2. SYN-ACK phi trạng thái [Cookie] ──│ (Hàm băm mật mã từ 4-tuple và ISN) │
│ │ │
│─── 3. TCP ACK [Cookie + 1] ────────────>│ │
│ │─── 4. Gửi TCP SYN nội bộ ────────────>│
│ │<── 5. Nhận SYN-ACK nội bộ [ISN máy] ──│
│ │─── 6. Phản hồi ACK nội bộ ───────────>│
│ │ │
│═════════════════════════════════════════╪═══════════════════════════════════════│
│ Giai đoạn truyền dữ liệu và điều chỉnh sai lệch số thứ tự │
│─── 7. Dữ liệu TLS / Ứng dụng ──────────>│─── 8. Viết lại SEQ/ACK (sai lệch) ───>│
│<── 10. Viết lại SEQ/ACK (sai lệch) ─────│<── 9. Dữ liệu phản hồi ───────────────│
Quy trình xử lý diễn ra qua 4 bước:
Bước 1: Tiếp nhận không ghi nhận trạng thái
Các gói SYN gửi tới cổng VPN được gắn nhãn notrack trong bảng raw prerouting. Thao tác này hướng dẫn Netfilter bỏ qua việc cấp phát cấu trúc struct nf_conn.
Bước 2: Tạo Syncookie phi trạng thái
Gói SYN chuyển tiếp tới chuỗi INPUT có gắn bộ lọc SYNPROXY. Thay vì chuyển gói vào hàng đợi socket, SYNPROXY tính toán số thứ tự ban đầu (ISN) 32-bit dựa trên thuật toán băm mật mã với các thông số:
- Địa chỉ IP nguồn và IP đích
- Cổng nguồn và cổng đích
- Số thứ tự ban đầu của máy khách
- Khóa bí mật nội bộ của nhân (được đổi mới định kỳ mỗi 60 giây)
- Các tùy chọn TCP nén (chỉ số MSS, hệ số nhân cửa sổ Window Scaling, cờ SACK)
SYNPROXY lập tức đóng gói và gửi trả gói tin SYN-ACK chứa giá trị syncookie này về máy khách. Toàn bộ tiến trình không hề tạo bất kỳ bộ nhớ hay đồng hồ hẹn giờ nào trong nhân. Nếu đây là gói tin giả mạo từ botnet, chuỗi giao tiếp kết thúc tại đây mà không làm hao tổn tài nguyên máy chủ.
Bước 3: Xác thực ACK và khởi tạo kết nối
Khi máy khách thật nhận được SYN-ACK, thiết bị sẽ gửi lại gói ACK mang số thứ tự Cookie + 1. SYNPROXY đón gói tin này, tính toán lại giá trị băm và đối chiếu tính hợp lệ.
Chỉ khi mã băm được xác thực chính xác, hệ thống mới tiến hành ghi nhận kết nối:
- Cấu trúc
struct nf_connchính thức được tạo trongnf_conntrack. - Trạng thái kết nối chuyển thẳng sang
ESTABLISHED. - Các thông số đàm phán TCP (dấu thời gian, SACK, kích thước cửa sổ) được giải mã từ syncookie và phục hồi đầy đủ.
Bước 4: Bắt tay nội bộ và điều chỉnh độ lệch số thứ tự
Do tiến trình VPN phía sau (như cổng TLS hoặc daemon trung chuyển) yêu cầu bắt tay 3 bước tiêu chuẩn, SYNPROXY tự động tạo một gói SYN nội bộ gửi vào socket cục bộ.
Khi tiến trình phản hồi bằng gói SYN-ACK chứa số thứ tự do ứng dụng sinh ra (ISN_server), SYNPROXY chặn lại và ghi nhận mức độ chênh lệch:
$$\Delta = ext{ISN}_{ ext{server}} - ext{Cookie}$$
Trong toàn bộ quá trình truyền dữ liệu sau đó, SYNPROXY tự động hiệu chỉnh tiêu đề gói tin ở tốc độ dây:
- Chiều đến: cộng thêm giá trị $\Delta$ vào trường Sequence Number.
- Chiều đi: trừ bớt giá trị $\Delta$ khỏi trường Acknowledgment Number.
Quá trình dịch chuyển này diễn ra hoàn toàn trong không gian nhân, giữ cho tầng ứng dụng hoạt động thông suốt mà không cần sửa đổi mã nguồn.
Triển khai thực tế: Thiết lập cấu hình nftables SYNPROXY
Để áp dụng cơ chế này, cấu hình tường lửa nftables được thiết lập với độ ưu tiên chuỗi phù hợp và quy tắc phân loại rõ ràng.
Tệp cấu hình hoàn chỉnh cho cổng dịch vụ TCP 443 trên gateway:
#!/usr/sbin/nft -f
flush ruleset
table inet vpn_filter {
# Khai báo các thông số đàm phán TCP cho synproxy
synproxy synproxy_vpn {
mss 1460
wscale 7
timestamp sack-perm
}
chain raw_prerouting {
type filter hook prerouting priority raw; policy accept;
# Loại bỏ theo dõi trạng thái cho các gói TCP SYN ban đầu trên cổng 443
tcp dport 443 tcp flags syn notrack
}
chain filter_input {
type filter hook input priority filter; policy drop;
# Chấp nhận lưu lượng loopback nội bộ
iif "lo" accept
# Cho phép các gói tin thuộc phiên kết nối đã xác lập
ct state established,related accept
# Loại bỏ các gói tin có trạng thái không hợp lệ
ct state invalid drop
# Điều hướng gói tin tới bộ phận xác thực SYNPROXY
tcp dport 443 synproxy config synproxy_vpn
# Chấp nhận kết nối hợp lệ sau khi bắt tay thành công
tcp dport 443 ct state new accept
}
chain filter_forward {
type filter hook forward priority filter; policy drop;
}
chain filter_output {
type filter hook output priority filter; policy accept;
}
}
Nạp cấu hình vào hệ thống bằng lệnh:
sudo nft -f /etc/nftables.conf
Kiểm tra trạng thái các bảng luật đã hoạt động:
sudo nft list table inet vpn_filter
Tinh chỉnh tham số nhân và giám sát vận hành
Để cơ chế SYNPROXY phát huy hiệu quả tối đa, các tham số mạng của nhân Linux cần được cấu hình đồng bộ.
Tạo tệp cấu hình /etc/sysctl.d/99-synproxy.conf:
# Bật tính năng syncookie trên nhân
net.ipv4.tcp_syncookies = 1
# Kích hoạt dấu thời gian TCP (bắt buộc để mã hóa window scale và SACK)
net.ipv4.tcp_timestamps = 1
# Tắt chế độ nhận diện lỏng lẻo để tránh chèn trạng thái giả mạo
net.netfilter.nf_conntrack_tcp_loose = 0
# Tối ưu kích thước bảng băm conntrack cho các phiên đã xác thực
net.netfilter.nf_conntrack_max = 2097152
net.netfilter.nf_conntrack_buckets = 524288
# Rút ngắn thời gian chờ giải phóng tài nguyên
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 10
net.netfilter.nf_conntrack_tcp_timeout_established = 3600
Kích hoạt các thiết lập mới:
sudo sysctl --system
Theo dõi số liệu thời gian thực
Quản trị viên có thể kiểm tra hiệu quả ngăn chặn tấn công qua giao diện /proc:
# Đọc số lượng kết nối đang được theo dõi
cat /proc/sys/net/netfilter/nf_conntrack_count
# Xem thống kê chi tiết của phân hệ SYNPROXY
cat /proc/net/stat/synproxy
Các chỉ số phản ánh tình trạng hoạt động:
entries: Số lượng kết nối đang do SYNPROXY quản lý.syn_received: Tổng số gói SYN được xử lý phi trạng thái.cookie_invalid: Số lượng gói ACK giả mạo hoặc lỗi thời bị loại bỏ.cookie_valid: Số lượng bắt tay hợp lệ chuyển tiếp thành công vào conntrack.
Ứng dụng trong kiến trúc gateway RiceGuard
Hệ thống bảo mật đa tầng đòi hỏi khả năng phòng ngự vững chắc trên mọi giao thức mạng. Mặc dù giao thức cốt lõi RiceGuard vận hành trên nền UDP với cơ chế xác thực cookie kép, các cụm máy chủ vẫn duy trì giao diện TCP kép nhằm hỗ trợ môi trường mạng công sở khắt khe và các dịch vụ truy vấn tên miền DNS qua HTTPS.
Việc tích hợp nftables SYNPROXY ngay tại biên mạng giúp gateway RiceGuard đứng vững trước các đợt càn quét lưu lượng lớn mà không làm tiêu hao bộ nhớ hay gây tắc nghẽn luồng xử lý gói tin mã hóa.



