Зөвхөн Docker контейнерын урсгалыг OpenVPN-ээр чиглүүлэх арга
Хостыг ердийн uplink дээрээ үлдээж, нэг контейнерын дэд сүлжээг туннелд хий: NAT дараалал, эх сурвалжийн дүрэм, OpenVPN iroute болон MSS шалгалт.
Контейнерын пакет хэзээ ч tun0 -д хүрдэггүй бөгөөд контейнер дээрх нэмэлт чадварууд үүнийг өөрчлөхгүй. Зочин ба туннелийн хооронд хоёр маршрутын хайлт байна: нэг нь зочины сүлжээний нэрийн орон зайд, нөгөө нь хүрээ гүүрэн дээр буусны дараа хост дээр, хоёр дахь нь өөр тохирлын дүрэмтэй өөр хүснэгтээс асууна. Миний лавлагааны зохион байгуулалт бол Linux хост бөгөөд дээр нь OpenVPN клиент ажилладаг, тэр нь 10.8.0.10 -г tun0 дээр барьдаг, 172.18.0.0/16 дээр Docker гүүр, зөвхөн туннелийн тал хүрч чадах хувийн хаяг байна. Зорилго нарийн хэвээр: тэр зочины дэд сүлжээ туннелээр гарч, хост ердийн uplink-ээ хадгална.
VPN клиентийг контейнер дотор ажиллуулах нь өөр загвар, богино зам биш. Тэгвэл контейнер өөрийн туннель, нэвтрэх мэдээллээ эзэмшиж, ажил iptables-д үлдэхгүй Dockerfile руу шилжинэ.
Дамжуулалт очих газраар маршрут сонгож, дараа нь NAT эх сурвалжийг дахин бичнэ
Тохируулсан үед net.ipv4.ip_forward=1 , дамжуулсан пакет үндсэн хүснэгтэд зөвхөн очих газраар чиглэгдэнэ. Эх сурвалж тэр шийдвэрт ямар ч үүрэггүй. Маршрут сонгогдсоны дараа л цөм POSTROUTING -г ажиллуулна, яг тэнд Docker-ийн өөрийн дүрэм байна: -s 172.18.0.0/16 ! -o br-appnet -j MASQUERADE. Гүүрнээс өөр интерфэйс рүү гарч буй бүхэн хөрвүүлэгдэж, ямар хаяг болох нь маршрут түүнийг аль интерфэйс рүү илгээснээс хамаарна.
Энэ дүрэм надад асуудаг шинж тэмдгүүдийн ихэнхийг тайлбарлана. Үндсэн хүснэгтэд хувийн очих газарт маршрут байхгүй бол пакет хостын физик хаягтайгаар uplink-ээр гарна. Таны үйлчилгээ үзүүлэгч очих газрыг хаяна, эсвэл алслагдсан сайт хэзээ ч хүлээгээгүй RFC 1918 эх сурвалжийг хаяна, туннель дээгүүр, эрүүл байхад контейнер хугацаа хэтэрнэ. tun0 дээрх бичлэг юу ч харуулахгүй, энэ нь тэмдэг юм. Хэрэв маршрут үнэхээр tun0 руу зааж байвал MASQUERADE эх сурвалжийг 10.8.0.10 руу дахин бичнэ, мөн тэр контейнер та юунд ч хүрэлгүй ажиллана.
Зочины эх сурвалжийг нэрлэсэн хайлтыг хүс. from ба iif байхгүй бол хост өөрийн сокетийн төлөө хариулж, дамжуулсан пакет хэзээ ч явахгүй замыг мэдээлнэ:
ip route get 192.168.11.222 from 172.18.0.5 iif br-appnetХэрэв тэр хариулт uplink-ийг нэрлэвэл туннель зурагт байхгүй, туннелийн талын ямар ч тохиргоо туслахгүй.
Зочиныг туннелийн өөрийн хаяг руу зөө
Хамгийн бага ажилладаг өөрчлөлт бол гарах үед эх сурвалжийг тодорхой дахин бичих юм. Нэмэхийн оронд оруул: Docker аль хэдийн POSTROUTING -ийн толгойд сууж байна, тиймээс -A -ээр нэмсэн дүрэм Docker-ийн дүрмийн дараа үнэлэгдэж, хэзээ ч ажиллахгүй.
iptables -t nat -I POSTROUTING 1 -s 172.18.0.0/16 -o tun0 -j SNAT --to-source 10.8.0.10Энэ тогтох эсэхийг хоёр нөхцөл шийднэ. Хаяг нь клиент үнэхээр эзэмшдэг хаяг байх ёстой, тиймээс клиент бүрт ifconfig-push 10.8.0.10 255.255.255.0 агуулсан бичлэгээр бэхэл; хэзээ ч олгогдоогүй хаягийг нэрлэсэн дүрэм алдаа биш, чимээгүй хасалт үүсгэдэг. Мөн алслагдсан тал тэр эх сурвалжийг хүлээн авч, хариултыг буцааж чиглүүлэх ёстой, тиймээс тэндхийн зөвшөөрлийн жагсаалт зочины дэд сүлжээг биш, туннелийн хаягийг нэрлэдэг. Клиентийн хаяг динамик үед -j MASQUERADE -тай -o tun0 интерфэйсийн байгаа зүйлийг дагана, гэхдээ тогтмол утгын эсрэг бичих боломжгүй алслагдсан бодлогын зардлаар.
Шүүлт нь нөгөө хагас. Docker FORWARD бодлогыг drop болгож, демон дахин эхлэх бүрт өөрийн эзэмшдэг гинжийг цэвэрлэдэг, тиймээс локал бодлогыг DOCKER-USER -д хий, тэр нь амьд үлддэг:
iptables -I DOCKER-USER -i br-appnet -o tun0 -j ACCEPT
iptables -I DOCKER-USER -i tun0 -o br-appnet -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPTБуцах дүрэм чухал: tun0 -д ирсэн хариулт гүүрээр нээсэн холболтод зөвхөн гарч буй чиглэл хүлээн авсан учраас хүлээн авагдахгүй.
Хостыг эх сурвалжийн дүрмээр шууд бари
Бүх гүүр туннелийг ашиглах ёстой, харин хост дээр өөр юу ч ашиглах ёсгүй бол NAT-ыг алгасаж, тэр эх сурвалжид өөрийн хүснэгтийг өг. Зочины хаягууд тэгвэл эхнээс эцэс хүртэл харагдана.
echo "200 vpnbox" >> /etc/iproute2/rt_tables
ip rule add from 172.18.0.0/16 lookup vpnbox pref 1000
ip route add default dev tun0 table vpnboxДүрмүүдийг үндсэн хүснэгтээс өмнө авч үзнэ, from эх сурвалжтай тохирно. Туннелийн өөрийн гадаад пакетууд хостын физик эх сурвалжийг зөөдөг тул тэд хэзээ ч from 172.18.0.0/16 -той тохирохгүй, туннель өөрийгөө дотогш буцааж чиглүүлж чадахгүй. Энэ өөрийгөө хасах нь зохион байгуулалтыг тогтвортой болгодог.
Буцах замд одоо тусламж хэрэгтэй. Алслагдсан тал хөрвүүлээгүй 172.18.0.x -г харж, түүний хаана байгааг мэдэх шалтгаангүй. Сервер дээр клиент бүрийн файлд iroute 172.18.0.0 255.255.0.0 хэрэгтэй, серверийн дотоод хүснэгт тэр угтварыг энэ клиентэд өгөхөд, мөн түлхсэн route 172.18.0.0 255.255.0.0 хэрэгтэй, бусад клиентүүд түүний байгааг мэдэхэд.
Итгэхийн өмнө хоёр шалгалт. Ажиллуул ip route show default -г: redirect-gateway def1 -тай хүснэгтэд 0.0.0.0/1 ба 128.0.0.0/1 байна tun0 -ээр, хост огт шууд биш, учир нь тэр хагас-өрөгдмөлүүд default -г орлуулахгүйгээр ялдаг. ip rule add -ээр нэмсэн дүрмүүд ч дахин ачаалахад алга болдог, тиймээс тэдгээрийг up скриптэд авч яв.
Багцын хэмжээ бол таны хийх хоёр дахь бүтэлгүйтэл
1500 байтын гүүрэн интерфэйс гадаад UDP, IP толгой нэмэгдэхэд туннельд даахаас илүүг өгдөг. Жижиг солилцоо өнгөрдөг тул DNS шийдэгдэж, TLS гар барилт дуусна, дараа нь том upload хаана ч алдаагүйгээр гацна. Илгээгч ижил сегментийн хэмжээг давтана, учир нь багасгахыг хэлэх ICMP фрагментацийн шаардлагын мэдээлэл хэзээ ч ирдэггүй.
Үүнийг интерфэйс, MSS эсвэл хоёуланд нь зас. Шахалага зочины хамтын ажиллагаа шаарддаггүй:
ip link set dev tun0 mtu 1400
iptables -t mangle -A FORWARD -o tun0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtuШахалага зөвхөн TCP-г дахин бичнэ. UDP, QUIC орсон, оронд нь доогуур зочины интерфэйс шаардана, --opt com.docker.network.driver.mtu=1400 -ээр сүлжээ үүсгэх үед эсвэл тохирох compose түлхүүрээр.
DNS болон давтах үнэ цэнэтэй шалгалтууд
Нэрийн шийдэл ижил замаар явна. Docker-ийн суулгагдсан шийдэгч 127.0.0.11 -д хостын тохируулсан серверүүд рүү дамжуулдаг тул контейнер хост ашиглаж буйг өвлөнө. Хувийн бүсийг зөвхөн туннелээр хүрэх шийдэгч хариулбал, зочиныг тэр хаяг руу чиглүүл, getent hosts -ээр контейнер дотор шалга, хост дээр биш.
- Бүтэлгүйтэж буй хүсэлтийг зочины дотор ажиллуул; хостын талын шалгалт өөр эх хаяг ашиглаж, асуудлыг нуудаг.
- Нэмсэн NAT, шүүлтийн дүрмийн тоолуурыг унш. Тохиролгүй дүрэм бол чиглүүлэлтийн алдаа, бодлогын алдаа биш.
- SNAT дүрэм дэх туннелийн хаяг клиент үнэхээр эзэмшдэг хаяг мөн эсэхийг батал.
- Серверийг гацаанд буруутгахаас өмнө зочины MTU-г буулга эсвэл MSS-ийг шах.
Жагсаалтаар доош явж, эхний бүтэлгүйтэл дээр зогс. Тэр давхаргыг засах ёстой; доогуур нэмсэн бүхэн зөвхөн хагарч буй хил хязгаарыг нуудаг.