Bypass cgroup của nftables cũng cần sửa địa chỉ nguồn
Đánh dấu một cgroup sẽ gửi nó sang bảng khác, và socket giữ nguyên địa chỉ mà nó đã có. Phân loại, định tuyến và dịch là ba bước riêng biệt.
Đánh dấu lưu lượng từ một cgroup là phần dễ. Ba quyết định riêng biệt phải khớp nhau trước khi một ứng dụng duy nhất đi ra qua giao diện vật lý trong khi mọi thứ khác vẫn ở trong đường hầm: socket nào thuộc ngoại lệ, tra cứu tuyến nào mà dấu kích hoạt, và địa chỉ nguồn nào mà gói mang theo khi nó rời đi. Hầu hết các lần thất bại làm đúng điều thứ nhất, làm nửa điều thứ hai và không bao giờ nhìn vào điều thứ ba.
Ba quyết định, không phải một
Phân loại trả lời ai được miễn. Định tuyến trả lời gói được đánh dấu đi đâu thay vào đó. Chọn nguồn trả lời đầu xa sẽ thấy gì và câu trả lời phải quay về đâu.
Những thứ này hỏng độc lập. Một gói có thể được phân loại, được định tuyến lại ra giao diện vật lý, và vẫn mang một địa chỉ riêng mà không bộ định tuyến thượng nguồn nào có thể trả về, tạo ra thời gian chờ trông giống hệt một lần chặn của tường lửa. Không có gì trong bước phân loại cảnh báo bạn về điều đó. Không có gì trong bước định tuyến cũng vậy.
Thứ tự cũng quan trọng. Phân loại xảy ra khi gói được tạo, định tuyến xảy ra sau đó, và dịch xảy ra tại điểm ra.
Nếu bạn không thể gọi tên giai đoạn nào trong ba giai đoạn bị hỏng, bạn không đang gỡ lỗi, bạn đang sắp xếp lại các quy tắc và hy vọng.
Khớp một cgroup vẫn sẽ tồn tại vào ngày mai
nftables có thể kiểm tra tư cách thành viên cgroup v2 của một socket, điều này thực sự hữu ích vì nó theo tiến trình chứ không theo đích. Cái bẫy là định danh. Một ứng dụng máy tính để bàn khởi chạy từ menu thường sống trong một scope tạm thời mà tên thay đổi ở lần khởi chạy tiếp theo.
nft list ruleset
systemctl status session.slice 2>/dev/null
cat /proc/self/cgroupSao chép tên scope từ một phiên và gán cứng nó tạo ra một quy tắc hoạt động hôm nay và âm thầm ngừng khớp vào ngày mai. Thay vào đó, hãy đặt ứng dụng vào một bối cảnh thực thi ổn định và có chủ đích, chẳng hạn như một scope hoặc unit riêng mà bạn kiểm soát, và khớp với nó. Quy tắc sau đó tồn tại qua các lần khởi động lại và cập nhật gói. Nó cũng trở thành thứ mà đồng nghiệp có thể suy luận mà không cần lịch sử phiên của bạn.
Cũng hãy chính xác về cơ chế bạn đang dùng. Phân loại net_cls của cgroup v1 và khớp socket của cgroup v2 là những thứ khác nhau, và một trường cùng tên trong tài liệu không làm chúng thay thế được cho nhau.
Chuỗi route là thứ kích hoạt tra cứu thứ hai
Với lưu lượng được tạo cục bộ, loại chuỗi quyết định liệu có gì xảy ra sau khi dấu được đặt. Một chuỗi output loại filter có thể đánh dấu gói và nhân sẽ tiếp tục dùng tuyến mà nó đã chọn. Một chuỗi loại route là cơ chế yêu cầu tra cứu mới.
table inet bypass {
chain mark {
type route hook output priority mangle; policy accept;
socket cgroupv2 level 2 "app.slice" meta mark set 0x1 comment "app bypass"
}
}
ip rule add fwmark 0x1 lookup 200
ip route add default via 203.0.113.1 dev wlan0 table 200Sau đó dấu cần một quy tắc chính sách gửi nó vào bảng, và bảng đó phải đầy đủ: tuyến mặc định, các đích cục bộ mà ứng dụng vẫn cần, và một cổng thượng nguồn thực sự trả lời.
Chọn giá trị dấu một cách có chủ đích. WireGuard dùng fwmark riêng cho lưu lượng vận chuyển bên ngoài, và việc vô tình rơi vào cùng con số có thể can thiệp vào ngoại lệ định tuyến của chính đường hầm theo những cách khó chẩn đoán.
Địa chỉ nguồn không đi theo tuyến
Một socket đã chọn địa chỉ nguồn cho đường đi của đường hầm sẽ giữ địa chỉ đó sau khi định tuyến lại. Không có gì trong thay đổi tuyến ghi lại nó, đó là lý do gói rời giao diện vật lý với một nguồn riêng mà mạng thượng nguồn không thể trả về.
Triệu chứng hữu hình là một ứng dụng có vẻ đang gửi dữ liệu và không bao giờ nhận được trả lời, và một nhật ký tường lửa không hiển thị gì vì gói không bao giờ quay lại.
Cách sửa hẹp là một quy tắc dịch nguồn giới hạn ở dấu của ứng dụng đó và giao diện ra thực của nó, tích hợp với NAT đã tồn tại thay vì thay thế nó:
table inet bypass {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
meta mark 0x1 oifname "wlan0" masquerade
}
}Chỉ dịch ngoại lệ và không gì khác. Một quy tắc masquerade bao trùm sửa triệu chứng và phá hủy khả năng nói lưu lượng nào đi theo đường nào. Khớp theo dấu, giao diện ra thực và, nếu có thể, địa chỉ của chính ứng dụng. Quy tắc rộng dễ viết và gần như không thể kiểm toán về sau.
Những gì vẫn thoát khỏi ngoại lệ
Phân giải tên có thể đến từ một tiến trình resolver riêng trong cgroup khác, nên phân loại socket của trình duyệt không phân loại các tra cứu của nó. Nếu các truy vấn của resolver vẫn ở trong đường hầm trong khi kết nối đi ra ngoài nó, các câu trả lời split-horizon có thể không khớp với đường đi. Sự không khớp đó tạo ra những lỗi trông giống lỗi DNS và không phải.
Tiến trình con kế thừa cgroup trong hầu hết các thiết lập, nhưng một trình trợ giúp tự chuyển mình vào scope riêng thì không. Hãy kiểm tra thay vì giả định, đặc biệt với bất cứ thứ gì tự thực thi lại.
Cuối cùng, hãy quyết định điều gì phải xảy ra khi đường hầm ngừng hoạt động. Một ngoại lệ âm thầm trở thành bypass hoàn toàn là một tư thế bảo mật khác với một ngoại lệ đóng lại khi hỏng, và chỉ một trong hai là điều bạn định.