Xử lý lỗi ICMP Black Hole: Khắc phục PMTUD trong mạng Tunneling

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

Kẻ tiêu diệt kết nối thầm lặng: ICMP Black Hole

Tôi đã từng dành cả ca làm việc để xử lý sự cố tại một văn phòng chi nhánh, nơi nhân viên có thể truy cập vào hệ thống chat nội bộ của công ty nhưng không thể mở được cổng thông tin tài liệu. Màn hình cứ thế đứng yên và xoay vòng liên tục. Đó không phải là do firewall chặn hay lỗi DNS. Đó là một lỗi ICMP Black Hole điển hình, gây ra bởi sự gián đoạn trong quá trình Path MTU Discovery (PMTUD).

Khi chúng ta đóng gói lưu lượng bên trong một tunnel (đường hầm)—như GRE, IPsec, hoặc VXLAN—chúng ta sẽ thêm các header bổ sung vào mỗi gói tin. Một frame Ethernet tiêu chuẩn có MTU (Maximum Transmission Unit) là 1500 bytes.

Nếu một tunnel IPsec thêm 60 bytes dữ liệu bổ sung (overhead), gói tin gốc sẽ không được vượt quá 1440 bytes. Khi một router nhận được gói tin quá lớn so với tunnel và bit “Don’t Fragment” (DF) được thiết lập, nó bắt buộc phải loại bỏ gói tin đó. Thông thường, router sẽ gửi lại một thông điệp ICMP “Destination Unreachable – Fragmentation Needed” để yêu cầu bên gửi thu nhỏ kích thước gói tin.

Một ICMP Black Hole xảy ra khi một chính sách bảo mật hoặc firewall cấu hình sai làm chặn (drop) thông điệp ICMP cụ thể đó. Server gửi sẽ không bao giờ nhận được thông tin về lỗi này. Nó tiếp tục truyền lại gói tin quá khổ cho đến khi kết nối cuối cùng bị hết thời gian chờ (timeout). Điều này giải thích tại sao các lệnh ping 64-byte hoạt động hoàn hảo, trong khi một phản hồi web 1400-byte lại luôn thất bại.

Thiết lập bộ công cụ chẩn đoán

Để khắc phục vấn đề, bạn cần các công cụ có thể tiết lộ những gì đang xảy ra ở cấp độ gói tin. Hầu hết các bản phân phối Linux đều bao gồm sẵn các công cụ này, nhưng bạn nên đảm bảo chúng đã được cập nhật trên máy chẩn đoán của mình.

Trên các hệ thống Ubuntu hoặc Debian, hãy cài đặt iputils-ping, tcpdump, và mtr. Đây là những công cụ thiết yếu để truy vết xem gói tin biến mất ở đâu.

# Cập nhật và cài đặt các công cụ mạng
sudo apt update
sudo apt install iputils-ping tcpdump mtr-tiny -y

Đối với người dùng RHEL, CentOS, hoặc Fedora, hãy chạy lệnh:

sudo dnf install iputils tcpdump mtr -y

Tôi đã sử dụng các công cụ này trong các môi trường thực tế để giải quyết vấn đề kết nối cho hàng trăm chi nhánh từ xa. Việc chuẩn bị sẵn sàng chúng giúp bạn ngừng phán đoán cảm tính và bắt đầu đo lường thực tế.

Cấu hình: Khắc phục sự sai lệch MTU và MSS

Bạn có thể giải quyết vấn đề này theo hai cách. Bạn có thể hạ MTU trên interface một cách thủ công, hoặc có thể sử dụng TCP MSS Clamping, đây là lựa chọn tối ưu và linh hoạt hơn cho các mạng hiện đại.

Cách 1: Điều chỉnh MTU thủ công

Nếu bạn quản lý các thiết bị của người dùng cuối hoặc interface tunnel cụ thể, bạn có thể hạ MTU trực tiếp. Đối với một tunnel GRE tiêu chuẩn, việc đặt MTU thành 1476 (1500 bytes trừ đi 24 bytes header của GRE) thường sẽ giải quyết được xung đột.

# Hạ MTU trên một interface cụ thể
sudo ip link set dev eth0 mtu 1400

Các thay đổi thủ công rất khó mở rộng quy mô. Nếu bạn có 500 máy tính xách tay, bạn sẽ không muốn phải chỉnh sửa từng cái một. Đây là lý do tại sao hầu hết các kỹ sư ưu tiên sử dụng MSS Clamping.

Cách 2: TCP MSS Clamping (Giải pháp chuyên nghiệp)

TCP Maximum Segment Size (MSS) xác định lượng dữ liệu lớn nhất mà một thiết bị chấp nhận trong một segment đơn lẻ. Trong quá trình bắt tay SYN/ACK ban đầu, cả hai bên sẽ thống nhất về giá trị này. Bằng cách “clamping” (giới hạn) MSS tại router, chúng ta buộc cả hai đầu cuối phải sử dụng các gói tin nhỏ hơn ngay từ byte đầu tiên.

Trên một gateway Linux sử dụng iptables, hãy áp dụng quy tắc này để tự động điều chỉnh MSS cho tất cả lưu lượng đi qua tunnel:

# Tự động giới hạn MSS theo PMTU
sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --clamp-mss-to-pmtu

Đối với các tunnel IPsec, vốn có lượng overhead khó dự đoán, tôi khuyên bạn nên đặt giới hạn cứng là 1360 bytes. Điều này tạo ra một biên độ an toàn cho các loại header mã hóa khác nhau.

# Thiết lập giá trị MSS cụ thể để đảm bảo an toàn cho IPsec
sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --set-mss 1360

Nếu bạn đang sử dụng nftables, hãy sử dụng cú pháp sau:

# Cú pháp tương đương trên nftables cho MSS clamping
nft add rule ip filter forward tcp flags syn tcp option maxseg size set 1360

Xác minh: Chứng minh giải pháp đã hoạt động

Sau khi áp dụng cấu hình, hãy xác minh rằng các gói tin lớn thực sự có thể đi qua đường truyền. Phương pháp hiệu quả nhất là sử dụng lệnh “Sweep Ping” với bit Don’t Fragment được kích hoạt.

Kiểm tra với Ping

Chạy một bài kiểm tra ping cấm phân mảnh. Bắt đầu với kích thước 1472 bytes (sẽ trở thành 1500 bytes kèm theo header) và giảm dần xuống.

# -M do: thiết lập bit Don't Fragment
# -s: kích thước dữ liệu gói tin
ping -M do -s 1472 1.1.1.1

Nếu bạn thấy lỗi “Frag needed and DF set,” nghĩa là MTU của bạn vẫn còn quá cao. Hãy giảm giá trị -s cho đến khi ping thành công. Nếu yêu cầu chỉ đơn giản là hết thời gian chờ (timeout), thì thông điệp lỗi ICMP vẫn đang bị chặn ở đâu đó phía trên (upstream).

Giám sát với tcpdump

Sử dụng tcpdump để theo dõi quá trình bắt tay TCP trong thời gian thực. Bạn cần xác nhận rằng gateway của mình đang ghi đè thành công giá trị MSS trong các gói tin SYN.

# Bắt các gói tin SYN để kiểm tra giá trị MSS
sudo tcpdump -i any -n "tcp[tcpflags] & (tcp-syn) != 0"

Kiểm tra trường options [mss XXXX] trong kết quả đầu ra. Nếu quy tắc của bạn hoạt động, bạn sẽ thấy 1360 (hoặc giá trị bạn đã chọn) thay vì giá trị mặc định 1460.

Lời kết

Để đảm bảo sự ổn định lâu dài, hãy kiểm tra chính sách ICMP trên firewall của bạn. Bạn nên luôn cho phép ICMP Type 3, Code 4. Nếu không có nó, PMTUD sẽ bị hỏng ngay từ khâu thiết kế. Bằng cách kết hợp MSS clamping với một giới hạn thận trọng khoảng 1350-1380 bytes, bạn có thể loại bỏ các lỗi mất kết nối bí ẩn thường gây khó khăn cho các môi trường VPN và SD-WAN.

Share: