Làm chủ bảng Linux Conntrack: Hướng dẫn theo dõi trạng thái Netfilter

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

Bộ điều phối lưu lượng âm thầm trong hệ thống

Máy chủ của bạn có thể có 64GB RAM và CPU chỉ hoạt động 2%, nhưng vẫn bị rớt mọi kết nối mới. Nghịch lý này thường chỉ ra một thủ phạm: conntrack. Là engine theo dõi trạng thái (stateful) của Netfilter, conntrack ghi nhớ mọi luồng dữ liệu mạng đi qua hệ thống. Đây là sổ cái ẩn giúp NAT hiện đại và tường lửa stateful hoạt động.

Tôi đã thấy nhiều kỹ sư dày dặn kinh nghiệm phải đau đầu khi bộ cân bằng tải (load balancer) gặp sự cố dưới mức tải trung bình. Thông thường, kernel đơn giản là đã hết không gian để theo dõi các ‘cuộc hội thoại’ mới. Việc làm chủ hệ thống con này là bắt buộc đối với bất kỳ ai đang quản lý các node Kubernetes lưu lượng cao hoặc các proxy Nginx bận rộn.

Stateless vs. Stateful: Tại sao chúng ta cần theo dõi kết nối

Hiểu về conntrack đòi hỏi chúng ta phải nhìn lại cách chúng ta từng lọc lưu lượng so với cách chúng ta làm hiện nay.

Lọc không trạng thái – Stateless (Kiểu cũ)

Tường lửa stateless coi mọi gói tin như một người lạ hoàn toàn. Để cho phép một yêu cầu web đơn giản, bạn phải mở thủ công một cổng đi và một đường về cụ thể. Nó nhanh nhưng cứng nhắc. Vì tường lửa không biết liệu một gói tin đến có thực sự được máy chủ của bạn yêu cầu hay không, nó khiến bạn dễ bị tấn công giả mạo (spoofing) cơ bản, điều thường được thử nghiệm khi mô phỏng tấn công và debug mạng.

Lọc có trạng thái – Stateful (Cách của Conntrack)

Conntrack giám sát quá trình bắt tay ba bước của TCP. Khi nó xác định được chuỗi SYN, SYN-ACK, và ACK, nó sẽ đánh dấu luồng đó là ESTABLISHED. Bạn chỉ cần một quy tắc để cho phép kết nối ban đầu. Netfilter sẽ tự động xử lý phần còn lại của cuộc hội thoại. Nó thậm chí còn nhận diện được lưu lượng “liên quan” (related), chẳng hạn như các thông báo lỗi ICMP được kích hoạt bởi một kết nối hiện có.

Sự đánh đổi khi theo dõi trạng thái

Lợi ích

  • Bảo mật chặt chẽ: Bạn có thể tự động loại bỏ bất kỳ gói tin nào không thuộc về một phiên đã được xác minh và đang diễn ra.
  • NAT liền mạch: Conntrack đóng vai trò là cơ sở dữ liệu ánh xạ các IP nội bộ sang IP công cộng, đảm bảo lưu lượng phản hồi tìm được đường quay về.
  • Nhận biết giao thức: Nó quản lý thông minh các giao thức phức tạp như FTP hoặc SIP vốn thường mở các cổng phụ một cách linh hoạt.

Rủi ro

  • Tiêu thụ bộ nhớ: Mỗi kết nối được theo dõi tốn khoảng 300 byte bộ nhớ kernel. Dù nhỏ, nhưng 1 triệu kết nối hoạt động sẽ tiêu tốn khoảng 300MB RAM.
  • Tràn bảng (Table Overflow): Bảng conntrack có một giới hạn cứng. Nếu bạn chạm ngưỡng này trong lúc lưu lượng tăng đột biến hoặc bị tấn công DDoS, kernel sẽ từ chối tất cả các kết nối mới.
  • Chi phí CPU: Việc kiểm tra mọi gói tin đối với một bảng trạng thái khổng lồ sẽ tốn nhiều tài nguyên hơn là chỉ định tuyến (routing) đơn thuần, khác với hiệu năng của XDP eBPF trên Linux.

Tinh chỉnh cho môi trường hiệu năng cao

Các bản phân phối Linux tiêu chuẩn thường đi kèm với các thiết lập mặc định khá dè dặt. Một máy chủ đóng vai trò là NAT gateway cho một văn phòng lớn hoặc một API bận rộn sẽ nhanh chóng vượt quá các thiết lập này. Dưới đây là cách tối ưu hóa hệ thống của bạn bằng sysctl để quản trị mạng chuyên nghiệp hơn.

1. Mở rộng dung lượng bảng

Hãy kiểm tra giới hạn hiện tại trước khi thay đổi. Nhiều hệ thống mặc định ở mức 65.536 mục, con số này quá thấp đối với các khối lượng công việc hiện đại.

# Xem giới hạn tối đa hiện tại
sysctl net.netfilter.nf_conntrack_max

# Xem có bao nhiêu kết nối đang được theo dõi
cat /proc/sys/net/netfilter/nf_conntrack_count

Đối với máy chủ có 16GB RAM, tôi thường đẩy giới hạn lên 1 triệu mục. Bạn cũng phải tăng kích thước bảng băm (hash table) để giữ tốc độ tra cứu nhanh. Tỷ lệ tốt là 1 bucket cho mỗi 8 mục.

# Đặt kết nối tối đa thành 1.048.576
sysctl -w net.netfilter.nf_conntrack_max=1048576

# Điều chỉnh hashsize (1048576 / 8 = 131072)
echo 131072 > /sys/module/nf_conntrack/parameters/hashsize

2. Rút ngắn thời gian chờ (Timeout)

Theo mặc định, Linux giữ một kết nối TCP “Established” trong bảng suốt 5 ngày. Điều này là quá mức cần thiết. Nếu ứng dụng của bạn tạo ra hàng nghìn kết nối ngắn hạn, bảng của bạn sẽ đầy rẫy các mục “ma” không còn hoạt động. Tôi khuyên bạn nên hạ thấp các giá trị này một cách đáng kể.

# Hủy các phiên đã thiết lập sau 1 giờ không hoạt động
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=3600

# Dọn dẹp các kết nối đã đóng nhanh hơn (trạng thái FIN_WAIT)
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_fin_wait=60

Công cụ và kỹ thuật khắc phục sự cố

Để xem điều gì đang xảy ra trong thời gian thực, hãy cài đặt gói conntrack-tools. Trên Debian hoặc Ubuntu, chạy lệnh sudo apt install conntrack.

Xác định các tác nhân gây tải lớn

Nếu mức sử dụng bảng của bạn tăng vọt, hãy sử dụng lệnh này để tìm xem IP nguồn nào đang mở nhiều kết nối nhất:

conntrack -L -o extended | awk '{print $7}' | cut -d= -f2 | sort | uniq -c | sort -nr | head -n 10

Lệnh này cung cấp một danh sách xếp hạng các IP, giúp bạn phân biệt giữa một dịch vụ nội bộ đang bận rộn và một cuộc tấn công botnet từ bên ngoài.

Lệnh xóa khẩn cấp

Đôi khi bạn cập nhật một quy tắc tường lửa, nhưng các kết nối “xấu” hiện có vẫn tồn tại vì chúng đã nằm trong bảng. Bạn có thể hủy các phiên cụ thể hoặc xóa toàn bộ bảng.

# Hủy tất cả kết nối từ một IP kẻ tấn công cụ thể
conntrack -D -s 203.0.113.10

# Xóa toàn bộ bảng (Cảnh báo: Hành động này sẽ tạm thời làm rớt các lưu lượng đang hoạt động)
conntrack -F

Theo dõi tình trạng rớt gói tin

Khi bảng chạm giới hạn, kernel sẽ ghi lại một lỗi rất cụ thể. Hãy kiểm tra log thường xuyên để tìm thông báo này:

dmesg | grep "nf_conntrack: table full, dropping packet"

Nếu thông báo này xuất hiện trong log, người dùng của bạn đang gặp tình trạng timeout. Bạn cần tăng nf_conntrack_max ngay lập tức hoặc tiến hành phân tích pcap chuyên sâu để kiểm tra lưu lượng.

Tổng kết

Conntrack là bộ máy thầm lặng của mạng Linux. Nó cung cấp trí thông minh cho bảo mật stateful, nhưng nó có giới hạn hữu hạn. Bằng cách mở rộng kích thước bảng và rút ngắn các timeout quá dài, bạn có thể ngăn chặn hầu hết các sự cố mạng “không rõ nguyên nhân”. Hãy luôn chuẩn bị sẵn công cụ CLI conntrack để xác định ai đang chiếm dụng các khe kết nối trên máy chủ của bạn.

Share: