Móc nối hai máy khách OpenVPN trên một máy chủ Linux bằng fwmark
Cả hai máy khách đều muốn tuyến mặc định. Ghim máy chủ bên trong bằng tuyến host, ngăn máy khách thứ hai ghi lại bảng, rồi điều hướng luồng bằng fwmark.
Xếp chồng máy khách OpenVPN thứ hai trên một máy chủ Linux thất bại ở một trong hai chỗ. Hoặc máy khách bên trong không đến được máy chủ của nó vì đường hầm bên ngoài đã chiếm mất luồng vận chuyển đó, hoặc máy khách thứ hai ghi lại bảng tuyến và đường hầm thứ nhất ngừng hoạt động. Cả hai vấn đề đều nằm ở định tuyến, không phải mã hóa, và cả hai được giải quyết trước khi đường hầm mới chở bất kỳ lưu lượng ứng dụng nào. Các địa chỉ ở đây chỉ là ví dụ: tun0 là đường hầm bên ngoài, 203.0.113.9 là máy chủ bên trong, và TCP 9999 là luồng phải dùng đường đi bên trong.
Hai kiểu hỏng, một bảng tuyến
Máy khách bên trong mở một ổ cắm UDP tới máy chủ của nó, và ổ cắm đó theo bảng tuyến hiện tại như mọi ổ cắm khác. Nếu đường hầm bên ngoài đã giữ tuyến mặc định, các gói bắt tay đi vào đường hầm bên ngoài. Điều đó chỉ hiệu quả khi máy chủ bên ngoài đến được máy chủ bên trong và phía bên kia đồng ý chở luồng; nếu không, quá trình bắt tay đình trệ và máy khách thử lại.
Lỗi thứ hai đến từ push của máy chủ. Push thông thường là redirect-gateway def1, nó cài 0.0.0.0/1 và 128.0.0.0/1 thay vì thay thế tuyến mặc định. Vì vậy hai máy khách mỗi bên cài cặp /1 của riêng mình sẽ đụng nhau, và cặp mới nhất thắng với gần như mọi đích. Hãy tìm hai tiền tố đó trong bảng khi một đường hầm chết sau khi cái thứ hai kết nối, vì bản thân tuyến mặc định có thể chưa bao giờ thay đổi.
Đánh dấu luồng và cấp cho nó một bảng
Điều hướng lưu lượng đã chọn bằng cách đánh dấu nó trong bảng mangle và khớp dấu trong một quy tắc chính sách. Quy tắc trỏ tới một bảng riêng có tuyến mặc định là thiết bị bên trong, nên chỉ các gói được đánh dấu mới đi theo đường bên trong.
iptables -t mangle -A PREROUTING -p tcp -m multiport --dport 9999 -j MARK --set-mark 0x9999
ip rule add fwmark 0x9999 table 200 pref 1000
ip route add default dev tun1 table 200Phần lớn lỗi trong bộ quy tắc này đến từ hai sai lầm. Giá trị dấu do tường lửa đặt và giá trị mà quy tắc khớp phải giống hệt nhau, vì sự lệch nhau không tạo ra lỗi cũng không tạo ra tác dụng. Và PREROUTING chỉ thấy các gói đến từ bên ngoài, nên một kết nối bắt đầu trên máy chủ này cần một quy tắc OUTPUT có cùng cách khớp trước khi nó được đánh dấu.
Lấy quyền sở hữu tuyến khỏi máy khách thứ hai
Hai tùy chọn ngăn máy khách thứ hai sửa bảng, và chúng tác động ở những điểm khác nhau. route-nopull bỏ qua các tùy chọn tuyến được push, nên không có gì được cài. route-noexec nhận các tùy chọn được push vào môi trường của máy khách nhưng để việc thay đổi bảng cho một hook, và đó chính là điều bạn muốn khi cần xem máy chủ đã đề nghị gì.
Hook chạy với các giá trị được push trong môi trường của nó, và chỉ nên thêm những mục bạn đã phê duyệt. Hãy làm nó idempotent: xóa sạch bảng mà nó sở hữu trước khi dựng lại, và đừng cho rằng lần chạy trước để lại trạng thái sạch. Việc kết nối lại gọi hook lần nữa, và một hook thêm vào mà không xóa sẽ tích tụ các tuyến trùng lặp.
Chọn một chủ sở hữu và ghi nó ra. Một hồ sơ đặt cả hai tùy chọn, hoặc một hook cạnh tranh với script thủ công, tạo ra một bảng mà sau này không ai giải thích được.
Ghim cả hai địa chỉ máy chủ
Máy chủ bên trong cần một tuyến host qua thiết bị bên ngoài trước khi máy khách bên trong kết nối. Chính mục đó giữ luồng vận chuyển bên trong ở trong đường hầm bên ngoài thay vì để nó theo tuyến mặc định.
ip route add 203.0.113.9/32 dev tun0
ip route get 203.0.113.9Cũng thêm một tuyến host tương ứng cho máy chủ bên ngoài vào bảng chính, nếu không việc kết nối lại có thể đưa luồng vận chuyển của chính máy khách bên ngoài vào đường hầm của nó. Thứ tự không phải tùy chọn: hãy thêm các mục này sau khi giao diện liên quan tồn tại, nghĩa là một hook hoặc script chạy sau khi kết nối. Một tuyến trỏ tới thiết bị đang tắt sẽ bị xóa hoặc bị bỏ qua, nên một mục viết lúc khởi động không sống sót qua trình tự bạn giả định.
Kiểm tra tra cứu thay vì đọc toàn bộ bảng. Kết quả tra cứu tuyến nêu thiết bị và địa chỉ nguồn mà kernel sẽ dùng, và đó đúng là thứ máy khách nhận được khi mở ổ cắm.
Kiểm thử chuỗi và làm lỗi hiện rõ
Bắt gói trên giao diện bên ngoài trong khi máy khách bên trong kết nối. Quá trình bắt tay bên trong phải xuất hiện dưới dạng tải trọng mã hóa bên trong đường hầm bên ngoài; nếu nó xuất hiện dưới dạng UDP trần tới 203.0.113.9, tuyến host bị thiếu và chuỗi chưa bao giờ được dựng.
Một chuỗi lặng lẽ quay về uplink vật lý là kết quả tệ nhất, vì trạng thái giao diện không thông báo gì và lưu lượng bên trong đi ra từ địa chỉ nguồn sai. Nếu máy khách thứ hai có thể kết nối lại trực tiếp khi đường hầm bên ngoài rớt, hãy tắt đường đó hoặc gắn nó vào giao diện bên ngoài để lỗi hiện rõ.
Kết thúc bằng hai luồng và một bản kết xuất quy tắc: kết nối được đánh dấu và không đánh dấu phải đi theo các đường khác nhau, và ip rule show phải liệt kê mức ưu tiên bạn dự định. Nếu cả hai luồng đi cùng một đường, dấu không được áp dụng ở nơi bạn nghĩ.