Search icon
/
VI
English
Português
Русский
Español
Türkçe
Українська
Tiếng Việt
ไทย
中文
हिंदी
Show menu icon

SOCKS5 UDP ASSOCIATE gây cạn kiệt cổng – Post-mortem

Kiến thức cơ bản
Đánh giá trung bình: 0.00 phiếu bầu
Author photo
Ilya Rusalowski2026-03-28
Clock icon4 phút

Gần một năm trước, chúng tôi triển khai một tính năng hoàn toàn tuân thủ RFC — và nó đánh sập production. Chúng tôi rollback, truy tìm nguyên nhân, và phát hiện vấn đề. Spoiler: không phải lỗi DNS. Mà là chúng tôi quên rằng cổng mạng là tài nguyên hữu hạn.

Cần proxy di động tư nhân?
Hãy tạo proxy di động ngay bây giờ!
Bắt đầu dùng thử miễn phí 48 giờ

TL;DR

Chúng tôi bổ sung hỗ trợ đầy đủ SOCKS5 UDP ASSOCIATE (RFC 1928) cho máy chủ proxy tại iProxy.online. Vài ngày sau, DNS ngừng phân giải, các tunnel bị ngắt, và nhiều dịch vụ liên tục timeout. Chúng tôi rollback và bắt đầu điều tra. Nguyên nhân gốc rễ là cạn kiệt cổng tạm thời (ephemeral port exhaustion) trên Linux — hàng nghìn phiên UDP ASSOCIATE, mỗi phiên giữ một cổng riêng, đã hút cạn toàn bộ pool cổng của hệ thống. Cách sửa chỉ gồm hai thay đổi cấu hình. Nhưng tìm ra vấn đề thì mất công hơn nhiều.

SOCKS5 UDP ASSOCIATE là gì?

SOCKS5, được định nghĩa trong RFC 1928, hỗ trợ ba lệnh: CONNECT (tunneling TCP), BIND (chấp nhận kết nối TCP đến), và UDP ASSOCIATE (chuyển tiếp gói tin UDP). Phần lớn nhà cung cấp proxy chỉ triển khai CONNECT. UDP ASSOCIATE là phần khó nhất — và cũng là phần quan trọng nhất cho các ứng dụng thời gian thực như VoIP, gaming, DNS-over-UDP, và QUIC.

Cơ chế hoạt động như sau:

  1. Client mở một kết nối TCP điều khiển đến máy chủ SOCKS5.

  2. Client gửi yêu cầu UDP ASSOCIATE qua kết nối TCP này.

  3. Server cấp phát một UDP socket riêng trên một cổng tạm thời và trả về địa chỉ cùng số cổng.

  4. Client gửi gói tin UDP đến cổng relay đó. Server chuyển tiếp đến đích và trả response ngược lại.

  5. Phiên kết nối tồn tại cho đến khi kết nối TCP điều khiển đóng hoặc hết thời gian chờ.

Mỗi phiên UDP ASSOCIATE đều chiếm một cổng tạm thời riêng trên server. Đây chính là chi tiết then chốt.

Và đây là cái bẫy. UDP không có kết nối (connectionless). Không có FIN, không có RST. Làm sao biết client đã xong để giải phóng cổng?

  1. Chờ kết nối TCP điều khiển đóng — tín hiệu theo RFC. Nhưng client có thể giữ kết nối mở vô thời hạn.

  2. Timeout khi không hoạt động. Nếu không có gói tin nào đến trong X giây, hệ thống sẽ hủy phiên. Nhưng nếu timeout quá cao, socket sẽ chồng chất.

Chúng tôi đặt timeout khá rộng rãi và không giới hạn số phiên mà một client có thể mở. Kết quả: socket chồng chất ngày càng nhiều.

Hệ thống của chúng tôi

Tại iProxy.online, chúng tôi vận hành hạ tầng proxy di động trên hơn 100 quốc gia và 600+ nhà mạng di động, biến điện thoại Android thật thành máy chủ proxy. Nếu bạn mới tìm hiểu, hướng dẫn xây dựng mạng proxy 4G của chúng tôi trình bày chi tiết kiến trúc hệ thống. Các máy chủ SOCKS5 backend xử lý hàng chục nghìn kết nối đồng thời.

Khoảng một năm trước, chúng tôi quyết định triển khai đầy đủ UDP ASSOCIATE — trở thành hoàn toàn tuân thủ RFC và mở ra những use case mà hầu hết đối thủ không hỗ trợ được: proxy VoIP, lưu lượng game, các giao thức dựa trên QUIC. Code triển khai đúng chuẩn. Test pass hết. Chúng tôi đưa lên production.


Xây dựng hạ tầng proxy ở quy mô này đồng nghĩa với việc mỗi quyết định về giao thức đều có hệ quả thực tế. Tại iProxy.online, mỗi thiết bị Android hoạt động như một máy chủ proxy di động độc lập — SOCKS5, HTTP, và giờ là cả UDP — quản lý qua dashboard hoặc Telegram bot. Nếu bạn muốn trải nghiệm hệ thống trước khi đọc về cách chúng tôi từng làm sập nó, dùng thử miễn phí 48 giờ — không cần thẻ tín dụng, chỉ từ $6/tháng.


Chuyện gì đã xảy ra

Vài ngày sau khi triển khai, các máy chủ production bắt đầu xuất hiện những triệu chứng kỳ lạ, thoạt nhìn không liên quan gì đến nhau:

  • DNS ngừng phân giải. Các dịch vụ nội bộ không thể tìm thấy nhau qua hostname.
  • Tunnel bị ngắt. Mất kết nối quản trị đến server.
  • Đồng bộ NTP thất bại. Đồng hồ server bắt đầu lệch.
  • Các dịch vụ UDP ngẫu nhiên timeout mà không có quy luật rõ ràng.

Sự cố không diễn ra từ từ — mà như rơi khỏi vách đá. Mọi thứ chạy bình thường hàng giờ liền, rồi đột nhiên nhiều dịch vụ cùng lúc sập trên cùng một host. Chúng tôi rollback UDP ASSOCIATE và bắt đầu truy tìm nguyên nhân.

Tìm ra nguyên nhân gốc rễ

Phản xạ ban đầu của chúng tôi sai hoàn toàn. Chúng tôi kiểm tra tấn công DDoS, rò rỉ bộ nhớ, I/O đĩa bão hòa, tải CPU — tất cả đều bình thường. Health check ở tầng ứng dụng vẫn xanh lè ngay trước thời điểm mọi thứ sụp đổ.

Bước đột phá đến từ các metric cấp hệ thống mà hầu hết đội ngũ vận hành không bao giờ để ý:

node_sockstat_UDP_inuse leo lên hàng chục nghìn. Trên server khỏe mạnh, con số này chỉ vài trăm. Server của chúng tôi vượt qua 20K.

ICMP Type 3 Code 3 (port unreachable) tăng vọt. Đây là kernel báo rằng "Tôi không thể cấp phát cổng nguồn cho gói UDP đi ra này."

Kiểm tra nhanh bằng tay xác nhận ngay:

ss -u state all | wc -l
# 28,431

cat /proc/net/sockstat
# UDP: inuse 28419

Dải cổng tạm thời mặc định trên Linux là 32768–60999 — khoảng 28.000 cổng. Chúng tôi đã tiêu thụ gần hết.

Hiệu ứng domino

Tính toán rất đơn giản. Linux có một pool cổng tạm thời hữu hạn — khoảng 28K theo mặc định. Mỗi phiên UDP ASSOCIATE chiếm một cổng. Hàng trăm phiên đồng thời cộng với thời gian giải phóng chậm, pool cạn kiệt nhanh chóng.

Khi hết cổng tạm thời, bất kỳ thứ gì trên server cần mở UDP socket mới đều thất bại. Bao gồm cả DNS — mỗi truy vấn DNS đi ra cần một cổng tạm thời để gửi request đến cổng 53. Phân giải tên miền chết, và đột nhiên mọi thứ trên server hỏng vì những lý do hoàn toàn không liên quan đến DNS.

Chuỗi sự cố diễn ra như sau:

Cấp phát cổng → mỗi phiên UDP ASSOCIATE gọi bind() với cổng 0, yêu cầu kernel cấp cổng tạm thời tiếp theo.

Tích lũy cổng → cổng giữ mở cho đến khi TCP đóng hoặc hết idle timeout. Timeout rộng rãi đồng nghĩa cổng tích tụ nhanh hơn tốc độ giải phóng.

Cạn kiệt pool → hàng nghìn phiên, mỗi phiên giữ một cổng, toàn bộ pool bị hút cạn. bind() bắt đầu trả về EADDRINUSE cho mọi socket mới.

Sập toàn hệ thống → truy vấn DNS thất bại (systemd-resolved cũng cần cổng tạm thời). WireGuard handshake thất bại. NTP thất bại. Syslog-over-UDP im lặng dừng hoạt động. Sau đó, lỗi DNS gây ra domino thứ cấp — bất kỳ thứ gì cần phân giải hostname đều ngừng hoạt động, bao gồm health check, kết nối database, và agent giám sát. Server trông như "chết" dù CPU, RAM, và ổ đĩa hoàn toàn bình thường.

Tại sao giám sát tiêu chuẩn bỏ lỡ

Health check qua HTTP vẫn pass — endpoint vẫn lắng nghe. CPU, RAM, ổ đĩa, throughput đều bình thường. Metric cấp process không có gì bất thường. Tiến trình SOCKS5 vẫn khỏe mạnh. Pool cổng của kernel mới là thứ bị cạn kiệt, và không có gì trong dashboard Grafana tiêu chuẩn theo dõi thông số này.

Những metric duy nhất phát hiện được vấn đề là những metric chúng tôi thêm gần như… cho có: bộ đếm socket cấp kernel và tỷ lệ lỗi ICMP.

Cách khắc phục

Sửa bằng hai thay đổi. Tìm ra lỗi mất thời gian hơn nhiều so với sửa lỗi.

1. Giảm mạnh idle timeout. Chúng tôi rút thời gian chờ không hoạt động cho phiên UDP ASSOCIATE từ vài phút xuống vài giây. Nếu không có gói tin nào đi qua cổng relay trong khoảng thời gian ngắn, phiên bị hủy và cổng được giải phóng. Hầu hết các phiên UDP hợp lệ (truy vấn DNS, NTP) hoàn thành trong chưa đầy một giây. Các phiên dài hạn (VoIP, gaming) duy trì phiên nhờ lưu lượng liên tục, nên không bị ảnh hưởng.

2. Giới hạn số phiên đồng thời mỗi client. Chúng tôi đặt giới hạn số phiên UDP ASSOCIATE mà một client có thể giữ cùng lúc. Điều này ngăn bất kỳ người dùng nào — hoặc client lỗi — chiếm hết pool cổng. Giới hạn đủ rộng cho sử dụng hợp lệ nhưng chặn được tích tụ mất kiểm soát.

Kết hợp hai biện pháp, UDP_inuse từ 28K giảm về vài trăm. Chúng tôi triển khai lại UDP ASSOCIATE với giới hạn mới, và hệ thống ổn định từ đó đến nay.


Bản sửa lỗi khá đơn giản — phần khó hơn là xây dựng hỗ trợ SOCKS5 UDP ASSOCIATE xử lý được hàng chục nghìn phiên đồng thời mà không hút cạn tài nguyên hệ thống. Nếu bạn cần proxy di động với UDP relay đầy đủ và quản lý vòng đời tài nguyên bài bản, iProxy.online chạy trên thiết bị Android thật tại 600+ nhà mạng, hỗ trợ xoay IP, quản lý từng thiết bị, và gói cước chỉ từ $6/tháng. Dùng thử miễn phí 48 giờ — test ngay trên tải thực tế của bạn.


Những gì bạn nên giám sát

Nếu bạn vận hành bất kỳ hệ thống nào mở UDP socket ở quy mô lớn — proxy SOCKS5, máy chủ game, hạ tầng VoIP, relay QUIC — hãy thêm các metric sau:

  1. node_sockstat_UDP_inuse (node_exporter). Số UDP socket đang mở theo thời gian thực. Server bình thường chỉ vài trăm. Nếu bạn dùng Prometheus, metric này đã có sẵn — chỉ cần tạo panel và cảnh báo. Khuyến nghị cảnh báo khi vượt 5.000.

  2. node_netstat_Icmp_OutDestUnreachs (ICMP Type 3 Code 3, port unreachable). Tăng đột biến nghĩa là kernel đang phản hồi gói UDP gửi đến cổng không có ai lắng nghe. Vài lần/phút là bình thường. Hàng nghìn lần/giây là cháy nhà.

  3. ss -u state all | wc -l — kiểm tra nhanh khi đang xử lý sự cố.

  4. cat /proc/net/sockstat — câu lệnh cổ điển, không cần cài thêm gì.

Những metric này không có trong hầu hết dashboard mặc định. Nhưng lẽ ra phải có. Để tìm hiểu thêm về duy trì hạ tầng proxy ổn định, xem hướng dẫn tối ưu tốc độ và độ ổn định proxy của chúng tôi.

Bài học rút ra

Cổng mạng là tài nguyên hữu hạn — hãy lên ngân sách cho chúng. Chúng tôi lên ngân sách cho CPU, RAM, ổ đĩa, và băng thông. Nhưng không ai tính đến cổng tạm thời. Trên server xử lý hàng chục nghìn kết nối, ~28K cổng thực ra rất ít. Bạn có thể mở rộng dải với sysctl -w net.ipv4.ip_local_port_range="1024 65535", nhưng ngay cả 64K cũng hữu hạn khi mỗi phiên giữ một cổng vô thời hạn.

RFC chỉ nói CÁI GÌ, không nói LÀM SAO. RFC 1928 được viết năm 1996 khi server "bận" chỉ xử lý vài trăm kết nối. Nó mô tả cơ chế giao thức hoàn hảo. Nhưng không đề cập gì đến quản lý vòng đời cổng, giới hạn tài nguyên, hay cơ chế suy giảm mềm. Nếu bạn triển khai bất kỳ giao thức nào ở quy mô lớn, hãy đọc RFC để đảm bảo đúng chuẩn, rồi tự thiết kế quản lý tài nguyên phía trên.

Metric kernel bắt được thứ metric ứng dụng bỏ lỡ. Health check, Prometheus scraper, và HTTP ping đều báo server khỏe mạnh. Kernel thì biết rõ hơn. Nếu giám sát của bạn không bao gồm thống kê socket và bộ đếm ICMP, bạn đang có điểm mù cho cả một lớp lỗi cạn kiệt tài nguyên. Chúng tôi từng gặp lỗ hổng quan sát tương tự với sự cố TLS 1.3 im lặng trên fleet thiết bị Android — nguyên nhân khác, bài học giống nhau.

UDP cần quản lý vòng đời tường minh. TCP có vòng đời sẵn — kết nối mở, truyền dữ liệu, và đóng với handshake rõ ràng. Cổng được tái sử dụng sau TIME_WAIT. UDP không có gì trong số đó. Socket mở cho đến khi có thứ gì đó chủ động đóng nó. Trong kiến trúc relay, bạn phải tự xây dựng cơ chế quản lý vòng đời, nếu không thì chấp nhận tiêu thụ tài nguyên không kiểm soát.

Ai nên lo lắng về vấn đề này

Đây không chỉ là vấn đề của proxy. Bất kỳ hạ tầng nào cấp phát UDP socket theo yêu cầu người dùng đều có thể gặp cùng kiểu sập:

  • Máy chủ TURN/STUN cho WebRTC — mỗi relay media cấp phát một cặp cổng.
  • Máy chủ game — mỗi phiên người chơi có thể giữ một cổng UDP.
  • QUIC load balancer — connection migration có thể dẫn đến tích tụ cổng.
  • DNS recursive resolver — mỗi truy vấn đi ra dùng một cổng tạm thời.
  • VPN concentrator — WireGuard và IPsec IKE đều dựa trên UDP.

Nếu bạn vận hành bất kỳ hệ thống nào trong số này ở quy mô lớn — hoặc đang triển khai hệ thống proxy di động — hãy kiểm tra sockstat hôm nay. Có thể bạn đang gần vách đá hơn mình tưởng.

Kết luận

Chúng tôi triển khai SOCKS5 UDP ASSOCIATE hoàn toàn đúng chuẩn — tuân thủ RFC, test đầy đủ, deploy thành công. Và nó gây ra sự cố toàn hệ thống mà giám sát tiêu chuẩn không phát hiện được.

Bài học mà giờ đây chúng tôi coi là nguyên tắc bắt buộc: bất kỳ tính năng nào cấp phát tài nguyên cấp kernel — cổng, file descriptor, conntrack entry — đều cần quản lý vòng đời tường minh và lên ngân sách tài nguyên từ ngày đầu tiên. Không phải sửa sau khi gặp sự cố lần đầu.

Cổng mạng giống như oxy. Bạn không nhận ra chúng tồn tại cho đến khi chúng cạn kiệt.


Đây là sự cố production thực tế từ iProxy.online. Chúng tôi xây dựng hạ tầng proxy di động biến điện thoại Android thành máy chủ proxy SOCKS5 và HTTP, hoạt động tại hơn 100 quốc gia và 600+ nhà mạng. Hỗ trợ đầy đủ UDP ASSOCIATE — giờ đã có quản lý tài nguyên bài bản. Tạo proxy di động ngay →

Câu hỏi thường gặp

SOCKS5 UDP ASSOCIATE là gì và hoạt động ra sao?

SOCKS5 UDP ASSOCIATE là một trong ba lệnh được định nghĩa trong RFC 1928. Nó cho phép client chuyển tiếp gói tin UDP qua proxy SOCKS5 bằng cách tạo một UDP socket riêng cho mỗi phiên. Khác với CONNECT (tunneling TCP), UDP ASSOCIATE xử lý lưu lượng connectionless — dùng cho DNS, VoIP, gaming, và giao thức QUIC.

Linux có bao nhiêu cổng tạm thời mặc định?

Linux sử dụng dải 32768–60999, tương đương khoảng 28.000 cổng. Kiểm tra dải hiện tại bằng cat /proc/sys/net/ipv4/ip_local_port_range và mở rộng bằng sysctl -w net.ipv4.ip_local_port_range="1024 65535" để có tối đa ~64.000 cổng. Ngay cả dải mở rộng cũng hữu hạn khi chạy UDP relay nặng.

Tại sao cạn kiệt cổng tạm thời lại giết chết DNS?

Mỗi truy vấn DNS đi ra cần một cổng tạm thời để gửi gói UDP đến cổng 53. Khi tất cả cổng tạm thời bị chiếm bởi các UDP socket khác, kernel không thể cấp phát cổng mới, và phân giải DNS thất bại trên toàn hệ thống — dù bản thân máy chủ DNS hoàn toàn khỏe mạnh.

Cách giám sát cổng tạm thời trên Linux như thế nào?

Theo dõi node_sockstat_UDP_inuse trong Prometheus/node_exporter để xem số UDP socket theo thời gian thực. Dùng ss -u state all | wc -l hoặc cat /proc/net/sockstat để kiểm tra thủ công. Đặt cảnh báo khi ICMP Type 3 Code 3 (port unreachable) tăng đột biến qua node_netstat_Icmp_OutDestUnreachs.

iProxy có hỗ trợ SOCKS5 UDP ASSOCIATE không?

Có. iProxy.online hỗ trợ đầy đủ SOCKS5 UDP ASSOCIATE cùng với CONNECT và HTTP proxy. Sau sự cố được mô tả ở trên, chúng tôi đã bổ sung giới hạn phiên mỗi client và idle timeout nghiêm ngặt để ngăn cạn kiệt cổng, trong khi vẫn duy trì UDP relay đầy đủ chức năng cho VoIP, gaming, và lưu lượng QUIC.


Dù bạn đang vận hành máy chủ TURN, hạ tầng game, hay mạng proxy di động, quản lý cổng tạm thời là vấn đề sống còn. iProxy.online mang đến SOCKS5 production-ready với UDP ASSOCIATE, quản lý qua dashboard và API, thiết lập trong chưa đầy 5 phút trên bất kỳ điện thoại Android nào. Dùng thử miễn phí 48 giờ — test ngay trên tải thực tế của bạn.

Đánh giá bài viết này, nếu bạn thích: