Cách một máy khách OpenVPN sau NAT trở thành lối ra internet
Lối ra tự quay số ra ngoài, nên bộ định tuyến của nó không cần cổng vào nào. Theo dõi những gì hub định tuyến, những gì lối ra chuyển tiếp và đường về bắt nguồn từ đâu.
Ba máy chủ Linux, một thiết kế: một hub OpenVPN truy cập công khai, một máy tính xách tay của người dùng và một máy lối ra nằm sau bộ định tuyến gia đình thông thường không chuyển tiếp gì vào trong. Lối ra tự gọi đến hub. Sau đó lưu lượng internet của người dùng đi vào đường hầm tại máy tính xách tay và ra ngoài qua đường lên riêng của lối ra. Mọi điều đáng ngạc nhiên trong cách bố trí này đều xuất phát từ một chi tiết: chính lối ra đã khởi tạo kết nối, nên đường vào đã tồn tại sẵn và không cần chuyển tiếp cổng để tạo ra nó.
Phần sau theo dõi đường đi của gói tin chứ không theo thứ tự cấu hình, vì cấu hình chỉ có nghĩa khi biết thành phần nào nắm giữ quyết định nào. Mỗi lớp nắm giữ đúng một quyết định, và lỗi tích tụ ở nơi hai lớp bị coi là một.
Hai phiên truyền tải, một đường bên trong
Mỗi máy chủ giữ kết nối bên ngoài riêng của nó tới hub, và không kết nối nào biết về kết nối kia. Lưu lượng của người dùng tới internet là một dòng chảy bên trong riêng biệt, tình cờ được mang bên trong đường hầm của người dùng rồi lại được phát ra từ đường hầm của lối ra. Chính dòng chảy bên trong đó là thứ hub phải định tuyến, và lối ra phải chuyển tiếp.
outer: consumer --TLS--> hub
outer: exit --TLS--> hub
inner: consumer --tun--> hub --internal--> exit --tun--> uplink
Vì cả hai kết nối bên ngoài đều đi ra từ phía máy khách, bộ định tuyến của lối ra không bao giờ thấy SYN đi vào và không bao giờ cần quy tắc NAT đích. Nó chỉ cần giữ cho đường truyền đã thiết lập còn sống, điều nó đã làm cho bất kỳ kết nối dài hạn nào. Không gì trên internet công cộng cần phải đến lối ra trước, đó là lý do địa chỉ động trên đường lên đó không phải vấn đề. Bộ định tuyến vẫn phải cho phép phiên đi ra, nhưng đó là cùng một quyền mà trình duyệt đã dùng.
iroute thực sự cài đặt gì bên trong máy chủ
Hub là thiết bị duy nhất quyết định đối tác nào sở hữu đích nào, và nó đưa ra quyết định đó trong bảng định tuyến không gian người dùng của chính nó, không phải trong bảng của nhân. Một mục client-config-dir cho lối ra tên là exit-node có thể yêu cầu tiền tố mặc định ở đó:
# /etc/openvpn/server/ccd/exit-node
iroute 0.0.0.0 0.0.0.0
Dòng đó nói với tiến trình máy chủ rằng "các gói bên trong với bất kỳ đích nào đều thuộc về máy khách này". Nó không thêm tuyến mặc định vào hệ điều hành của hub và không biến hub thành cổng internet. Tài liệu tham chiếu OpenVPN 2.6 giữ định tuyến bên trong riêng cho máy khách và định tuyến của nhân như hai cơ chế tách biệt, và chính sự tách biệt đó là lý do thiết kế này hoạt động mà không chạm vào tuyến mặc định của hub.
Người dùng cần chỉ dẫn đối xứng, được gửi dưới dạng push, để lưu lượng của chính họ đi vào đường hầm thay vì ra ngoài qua cổng cục bộ. Với tô-pô mạng con, nhóm là một tuyến kết nối trên thiết bị tun của lối ra, nên chiều về không cần push thêm; điều lối ra không được nhận là chuyển hướng bên dưới, thứ sẽ gửi lưu lượng đường lên của chính nó trở lại đường hầm mà nó đang cố dùng. Chỉ gửi nó cho người dùng và đọc các tuyến đã áp dụng trên máy khách thay vì tin rằng tệp CCD đã được chọn.
# /etc/openvpn/server/ccd/consumer-01
push "redirect-gateway def1"
Nhân của lối ra thực hiện việc chuyển tiếp
Bên trong lối ra, một gói từ người dùng đến giao diện tun được gửi tới một máy chủ internet nào đó. Nhân tra bảng định tuyến của mình, tìm đường lên thực sự là khớp tốt nhất rồi áp dụng hai chính sách độc lập: gói này có được chuyển tiếp hay không, và nó có thể rời giao diện đó với địa chỉ nguồn đó hay không. Chuyển tiếp là một sysctl, và nó bị tắt theo mặc định trên nhiều bản phân phối.
Vậy lối ra cần bật chuyển tiếp IPv4 thường trực, một quy tắc cho phép các nguồn của đường hầm người dùng đi về phía đường lên, và đường trả lời quay lại qua tun. Bật chuyển tiếp cho toàn bộ máy chủ cũng thay đổi hành vi của mọi thứ khác được định tuyến qua nó, nên quy tắc nên nêu tên các nguồn và giao diện thay vì chấp nhận mọi thứ.
Đường về được mua bằng dịch địa chỉ nguồn
Một máy chủ internet không có tuyến tới địa chỉ 10.90.0.x, nên các câu trả lời sẽ bị bỏ trước khi đến được lối ra. Việc viết lại nguồn khi gói rời đường lên giải quyết điều đó, và theo dõi kết nối đảo ngược việc viết lại trên đường về.
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -s 10.90.0.0/24 -o enp1s0 -j MASQUERADE
ip -4 route get 10.90.0.9 # run on the exit: must point at the tun
Quy tắc trên là điểm khởi đầu cho một giao diện đường lên, không phải chính sách tường lửa. Thu hẹp nguồn về đúng những phân bổ bạn thực sự cho phép, và giữ chính sách đầu vào riêng của lối ra tách biệt, để việc giả mạo địa chỉ cho lưu lượng đường hầm không âm thầm phơi bày dịch vụ cục bộ. Trên máy chủ có địa chỉ đường lên động, việc giả mạo cũng giúp bạn khỏi phải theo dõi địa chỉ bằng tay.
Nơi hub có thể thực thi và nơi không thể
Với client-to-client và đường dữ liệu không gian người dùng truyền thống, hub chuyển các gói bên trong giữa các đối tác ngay trong tiến trình máy chủ. Chúng không bao giờ đi qua chuỗi FORWARD của nhân hub, nên một quy tắc nhân ở đó không thể hạn chế việc đi lại giữa các đối tác, dù được viết cẩn thận đến đâu. Việc thực thi phải nằm trong chính sách của máy chủ: ai được phép kết nối, nhận tệp CCD nào và quyền sở hữu mặc định của lối ra có được cấp hay không.
Đó là lý do iroute mặc định là một quyết định tin cậy rộng. Lối ra phải chấp nhận hợp pháp lưu lượng về từ các địa chỉ internet tùy ý, và nó phải là cỗ máy bạn kiểm soát, vá và giám sát. Trao cùng quyền sở hữu đó cho một đối tác mà bạn không giao bộ định tuyến chính là sai lầm mà thiết kế này mời gọi.
Tư cách thành viên là sự kiểm soát thực sự. Bất kỳ máy khách nào tự cấu hình được tuyến của mình đều có thể thử dùng lối ra, nên việc hạn chế ai được kết nối, hoặc lối ra phục vụ những đối tác nào, là một phần của thiết kế chứ không phải ý nghĩ thêm sau.
Thất bại an toàn khi lối ra biến mất
Tắt lối ra và quyền sở hữu mặc định bên trong biến mất cùng phiên của nó. Điều không được xảy ra là hub âm thầm trở thành lối ra thay thế: không có tuyến mặc định từ nhóm VPN tới đường lên của hub, và không có quy tắc giả mạo rộng trên hub sẵn lòng chuyển tiếp cùng lưu lượng đó. Hãy thử thất bại đó một cách có chủ đích, rồi thử phục hồi bằng một dòng chảy mới chứ không phải trang đã mở sẵn.
# on the consumer, with the exit up and then down
ip -4 route get 1.1.1.1
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com
Nếu lưu lượng của người dùng vẫn đến được internet sau khi lối ra biến mất, thì thứ khác đang mang nó và ranh giới bạn định không tồn tại. Coi DNS và IPv6 cũng là những quyết định riêng: tuyến IPv4 cộng giả mạo không nói gì về lưu lượng AAAA, và trình phân giải do hub đẩy xuống sẽ trả lời từ nơi truy vấn thực sự đi ra.