Khi kết nối TCP ở trạng thái TIME_WAIT nhận gói SYN cùng bộ tứ, hệ thống xử lý như thế nào?

Trong quá trình phân tích hành vi của giao thức TCP dưới Linux, một tình huống thường gây nhầm lẫn là phản ứng của socket đang ở trạng thái TIME_WAIT khi nhận phải gói SYN có cùng bộ tứ (source IP, source port, destination IP, destination port). Nhiều tài liệu sơ lược cho rằng kernel sẽ gửi ngay gói RST, nhưng thực tế lại phụ thuộc vào tính hợp lệ của hai yếu tố then chốt: **số thứ tự (sequence number)** và **nhãn thời gian (timestamp)** — nếu cơ chế TCP Timestamp được kích hoạt. Dưới đây là mô tả chi tiết cách nhân Linux (phiên bản 4.2+) xử lý gói SYN trong trạng thái TIME_WAIT, dựa trên phân tích mã nguồn và logic kiểm tra đầu vào.

Điều kiện để một gói SYN được coi là "hợp lệ"

Tính hợp lệ không chỉ phụ thuộc vào số thứ tự, mà còn bị ảnh hưởng bởi việc có sử dụng TCP Timestamp hay không:
  • Khi cả hai bên bật TCP Timestamp:
    Gói SYN được coi là hợp lệ nếu đồng thời thỏa mãn:
      • SYN.seq > tw_rcv_nxt (số thứ tự lớn hơn giá trị kỳ vọng tiếp theo),
      • SYN.tsval > tw_ts_recent (nhãn thời gian mới lớn hơn nhãn thời gian gần nhất đã ghi nhận).
  • Khi không dùng TCP Timestamp:
    Chỉ cần kiểm tra điều kiện về số thứ tự: SYN.seq > tw_rcv_nxt.

Xử lý khi nhận gói SYN hợp lệ

Nếu điều kiện trên được đáp ứng, hàm tcp_timewait_state_process() trả về giá trị TCP_TW_SYN. Hệ thống sẽ:
  • Bỏ qua giai đoạn chờ 2MSL,
  • Chuyển trạng thái từ TIME_WAIT sang SYN_RECV,
  • Khởi tạo lại tham số kết nối (ví dụ: sinh lại ISN bằng công thức tw_snd_nxt + 65535 + 2),
  • Tiếp tục quy trình bắt tay ba bước như bình thường.
Ví dụ minh họa:
Giả sử tại thời điểm kết thúc FIN-WAIT-2:
  tw_rcv_nxt = 301
  tw_ts_recent = 21

Gói SYN nhận được có:
  seq = 400, tsval = 30

→ 400 > 301 ✅ và 30 > 21 ✅ → HỢP LỆ → Trả về TCP_TW_SYN.

Xử lý khi nhận gói SYN không hợp lệ

Khi điều kiện không thỏa mãn, hàm trả về TCP_TW_ACK. Hệ thống sẽ:
  • Gửi lại gói ACK giống hệt lần cuối (tức ACK của FIN thứ ba trong tiến trình đóng kết nối),
  • Gói này có ack_num không khớp với seq của gói SYN nên phía client sẽ phản hồi RST,
  • Client sau đó sẽ tiến hành tái truyền SYN theo cơ chế timeout – nếu vượt ngưỡng tối đa, kết nối bị hủy.
Ví dụ minh họa:
Giả sử:
  tw_rcv_nxt = 301, tw_ts_recent = 21
SYN nhận được có:
  seq = 200, tsval = 15

→ 200 < 301 ❌ → KHÔNG HỢP LỆ → Trả về TCP_TW_ACK.

Cơ chế xử lý RST trong TIME_WAIT

Hành vi khi nhận RST phụ thuộc vào tham số kernel net.ipv4.tcp_rfc1337:
  • tcp_rfc1337 = 0 (mặc định): Hệ thống hủy bỏ ngay TIME_WAIT, giải phóng socket — nhưng tiềm ẩn rủi ro tái sử dụng sớm gây xung đột dữ liệu cũ.
  • tcp_rfc1337 = 1: Bỏ qua gói RST, duy trì trạng thái đầy đủ 2MSL — tuân thủ đúng RFC 1337 nhằm đảm bảo tính toàn vẹn của luồng kết nối.
Đây là một phần quan trọng trong thiết kế TIME_WAIT, vốn phục vụ hai mục tiêu cốt lõi:
  1. Ngăn dữ liệu sót lại từ phiên kết nối cũ bị nhầm lẫn là của phiên mới (cùng bộ tứ),
  2. Đảm bảo bên bị động đóng (passive close) nhận đủ ACK cuối cùng để kết thúc sạch sẽ.
Do đó, việc giữ nguyên TIME_WAIT không phải là "lỗi hiệu năng", mà là một cơ chế bảo vệ chủ động. Như ghi chú trong UNIX Network Programming: "TIME_WAIT is your friend."

Thẻ: TCP TIME_WAIT linux-kernel Networking

Đăng vào ngày 24 tháng 5 lúc 23:32