Ai đó yêu cầu trình duyệt dùng đường hầm, và câu trả lời quay về dưới dạng quy tắc tường lửa khớp với cổng đích 80 và 443. Nó trông chính xác và không phải vậy. Khớp cổng chọn gói theo tiêu đề truyền tải, không theo chương trình nào đã mở socket, và duyệt web hiện đại không giới hạn ở hai cổng đó trên TCP. Quy tắc sẽ bỏ sót phần lưu lượng bạn muốn bao gồm và bắt lấy lưu lượng bạn chưa bao giờ định chạm tới. Trước khi viết nó, hãy quyết định bạn thực sự muốn ranh giới nào trong ba ranh giới khác nhau.

Quy tắc mô tả một lớp truyền tải, không phải ứng dụng

Trên Linux, khớp cổng đích kiểm tra tiêu đề TCP và không gì phía trên nó. Đánh dấu các gói đó và điều hướng bằng tuyến chính sách hoạt động đúng như tài liệu, và không cơ chế nào trong số đó biết tải trọng nghĩa là gì hay tiến trình nào đã gửi nó. Dấu là một con số gắn với gói, không phải danh tính gắn với ứng dụng.

nft add rule inet mangle output tcp dport { 80, 443 } meta mark set 0x1
ip rule add fwmark 0x1 table 100
ip route add default dev wg0 table 100

Hai hệ quả đến ngay. Trình cập nhật phần mềm kết nối TCP 443 nhận cùng cách đối xử như trình duyệt, có thể ổn hoặc có thể là gián đoạn đang chờ chu kỳ cập nhật tiếp theo. Và một dịch vụ web cố ý công bố trên cổng khác, giả sử 8443, rơi hoàn toàn ra ngoài quy tắc dù đó vẫn là lưu lượng web mà người dùng quan tâm.

Các con số là bộ chọn hợp lệ khi yêu cầu thực sự về những cổng đó. Chúng trở thành hư cấu khi phiếu yêu cầu ghi «trình duyệt» và một dải cổng được triển khai trong bộ quy tắc. Khoảng trống đó không phải là tiểu tiết tài liệu. Đó là khác biệt giữa quy tắc bạn có thể bảo vệ trong buổi đánh giá và quy tắc không ai có thể kiểm thử.

HTTP/3 lặng lẽ rời bỏ quy tắc TCP của bạn

HTTP/3 chạy trên QUIC, và QUIC được chở trong UDP. Một quy tắc chỉ khớp TCP không thể thấy nó, nên cùng trình duyệt đã vượt trang kiểm thử của bạn có thể gửi yêu cầu sau đó qua UDP và lách đường hầm mà không ai đổi cài đặt. RFC 9114 mô tả HTTP/3 là giao thức dựa trên QUIC, và QUIC dùng UDP với cổng mặc định 443 trong triển khai thông thường.

Việc một trình duyệt cụ thể có thử HTTP/3 hay không phụ thuộc cấu hình của nó, trang web và việc lần thử trước có thành công. Điều đó khiến nó là thứ khó suy luận từ trí nhớ. Hãy hỏi công cụ:

curl --http3 -sS -o /dev/null -w '%{http_version} %{time_total}\n' https://example.com
ss -tunp | grep -E ':443\b'

Dòng curl in ra phiên bản đã thương lượng, nên 3 xác nhận đường UDP đã được dùng. Danh sách socket sau đó cho biết kết nối ấy gắn với giao diện đường hầm hay giao diện vật lý. Nếu bản curl của bạn không có HTTP/3, cờ sẽ thất bại ồn ào thay vì lặng lẽ lùi lại, đó là lòng thương nhỏ của riêng nó.

DNS là một quyết định riêng bạn phải đưa ra

Quy tắc cổng cho lưu lượng web không nói gì về phân giải tên. Trình duyệt có thể dùng trình phân giải hệ thống, trình phân giải cấu hình bên trong trình duyệt, hoặc một trình do kết nối cuối cùng đẩy vào. Mỗi cái trong đó có thể gửi truy vấn theo đường khác với đường quy tắc của bạn chọn, tạo ra sự chia cắt kinh điển: trang tải, tên được phân giải ở nơi bạn không ngờ, và trang nội bộ phân giải thành địa chỉ công cộng hoặc không phân giải được.

Hãy quyết định điều đó một cách rõ ràng. Nếu tên nội bộ phải phân giải qua đường hầm, trình phân giải phải nằm bên trong nó, và bộ quy tắc phải cho phép DNS tới trình phân giải đó đồng thời giữ các truy vấn khác ở ngoài. Nếu trình duyệt dùng DNS over HTTPS tới nhà cung cấp công cộng, truy vấn bỏ qua hoàn toàn trình phân giải của bạn và quy tắc cổng không thể giúp. Hãy ghi lựa chọn vào cùng bản ghi thay đổi với quy tắc định tuyến, vì người gỡ lỗi sự cố tiếp theo sẽ đọc cả hai cùng lúc.

Sau đó hãy xác minh bằng trình phân giải chứ không phải bằng trang:

resolvectl query intranet.example.internal
resolvectl status | grep -A3 'Current DNS Server'

Không có câu trả lời là vấn đề phân giải ngay cả khi thông báo lỗi của trình duyệt đổ lỗi cho mạng. Hai sự cố này trông giống hệt nhau với người dùng và là hai phiếu hoàn toàn khác nhau.

Ba ranh giới, ba cơ chế khác nhau

Phần lớn sự nhầm lẫn biến mất khi bạn đặt tên cho ranh giới mình muốn. Chúng không thay thế cho nhau, và mỗi cái có kiểu hỏng khác nhau khi đường hầm sập.

What you actually wantMechanism that fitsWhat it does not cover
These transport ports use this exitFirewall mark plus policy routeApplications, HTTP/3 over UDP, DNS
This browsing session stays separateApplication-aware VPN, or a separate network namespace plus a proxyOther applications in the same session
Only these private sites are reachableDestination-based routes with private DNSPublic sites on the same address family

Một hồ sơ trình duyệt riêng là cái bẫy ở hàng giữa. Nó tách cookie và lịch sử, và không thay đổi gì trong bảng định tuyến của máy chủ, nên cả hai hồ sơ đi cùng một đường. Cách ly đòi hỏi thứ gì đó mà nhân hệ điều hành cưỡng chế, tức là không gian tên, container hoặc một ứng dụng có giao diện đường hầm riêng.

Dù hàng nào áp dụng, hãy viết ra điều gì phải xảy ra khi đường hầm sập. Một tuyến dựa trên dấu biến mất cùng giao diện thường rơi về tuyến mặc định vật lý, đó là hành vi fail-open. Điều đó có thể chấp nhận cho duyệt web và không chấp nhận cho mọi thứ khác, và đó là quyết định, không phải chi tiết triển khai.

Hãy kiểm thử những luồng bạn cho là đã bao phủ

Bài kiểm thử chấp nhận phải theo ranh giới bạn đã viết, không theo số cổng thuận tiện. Chọn một luồng phải đi qua đường hầm, một luồng không được đi, và một luồng dùng kiểu truyền tải bạn chưa nghĩ tới:

ip route get 203.0.113.40
curl -sS -o /dev/null -w 'v4 %{http_version} %{remote_ip}\n' https://example.com
nft list ruleset | grep -A2 'dport'

Tra cứu tuyến cho bạn biết đích thực sự dùng giao diện nào, và đó là sự thật mà hầu hết báo cáo nói sai. Dòng curl xác nhận phiên bản đã thương lượng và họ địa chỉ. Bản kết xuất bộ quy tắc bắt được quy tắc bạn thêm khi kiểm thử và quên giới hạn, và đó là cách một dấu tạm thời trở thành định tuyến fail-open vĩnh viễn.

Ghi lại cả ba kết quả với dấu thời gian và lưu cùng thay đổi. Khi về sau ai đó báo rằng «VPN đã làm hỏng mạng nội bộ», khác biệt giữa ranh giới dự định và ranh giới đã triển khai sẽ hiện ra trong bản ghi đó, và cách sửa sẽ là thay đổi quy tắc chứ không phải tranh luận.

Bài viết liên quan