ફક્ત Docker કન્ટેનરનો ટ્રાફિક OpenVPN દ્વારા કેવી રીતે રૂટ કરવો
હોસ્ટને તેના સામાન્ય અપલિંક પર રાખો અને એક કન્ટેનર સબનેટને ટનલમાં મૂકો: NAT ક્રમ, સ્રોત નિયમો, OpenVPN iroute અને MSS તપાસ.
કન્ટેનરનું પેકેટ ક્યારેય tun0 સુધી પહોંચતું નથી, અને કન્ટેનર પરના વધારાના ક્ષમતાઓ તેને બદલશે નહીં। અતિથિ અને ટનલ વચ્ચે બે રૂટ લુકઅપ છે: એક અતિથિના નેટવર્ક નામસ્થાનની અંદર, એક હોસ્ટ પર ફ્રેમ બ્રિજ પર ઉતર્યા પછી, અને બીજું જુદા મેચ નિયમોવાળા જુદા ટેબલને પૂછે છે। મારું સંદર્ભ લેઆઉટ એ Linux હોસ્ટ છે જે OpenVPN ક્લાયન્ટ ચલાવે છે, જે 10.8.0.10 ને tun0 પર રાખે છે, 172.18.0.0/16 પર Docker બ્રિજ, અને એક ખાનગી સરનામું જે ફક્ત ટનલની બાજુ જ પહોંચી શકે છે। લક્ષ્ય સાંકડું જ રહે છે: તે અતિથિ સબનેટ ટનલ દ્વારા બહાર જાય છે જ્યારે હોસ્ટ તેનું સામાન્ય અપલિંક રાખે છે।
કન્ટેનરની અંદર VPN ક્લાયન્ટ ચલાવવો એ બીજી રચના છે, કોઈ શોર્ટકટ નહીં. પછી કન્ટેનર પોતાની ટનલ અને ઓળખપત્રોનું માલિક હોય છે, અને કામ iptables માં રહેવાને બદલે Dockerfile માં જાય છે।
ફોર્વર્ડિંગ ગંતવ્ય દ્વારા રૂટ પસંદ કરે છે, પછી NAT સ્રોત ફરીથી લખે છે
જ્યારે net.ipv4.ip_forward=1 સેટ હોય, ત્યારે ફોર્વર્ડ કરેલું પેકેટ ફક્ત ગંતવ્ય દ્વારા, મુખ્ય ટેબલમાં રૂટ થાય છે। તે નિર્ણયમાં સ્રોતનો કોઈ ભાગ નથી। રૂટ પસંદ થયા પછી જ કર્નલ POSTROUTING ચલાવે છે, અને ત્યાં જ Dockerનો પોતાનો નિયમ બેસે છે: -s 172.18.0.0/16 ! -o br-appnet -j MASQUERADE। બ્રિજ છોડીને બીજા ઇન્ટરફેસ તરફ જતું દરેક વસ્તુ અનુવાદિત થાય છે, અને તે જે સરનામું બને છે તે રૂટે તેને મોકલેલા ઇન્ટરફેસ પર આધાર રાખે છે।
તે નિયમ મને પૂછાતા મોટા ભાગના લક્ષણો સમજાવે છે। જો મુખ્ય ટેબલમાં ખાનગી ગંતવ્ય માટે રૂટ ન હોય, તો પેકેટ હોસ્ટના ભૌતિક સરનામા સાથે અપલિંક દ્વારા બહાર જાય છે। તમારો પ્રદાતા ગંતવ્ય કાઢી નાખે છે, અથવા દૂરની સાઇટ એવો 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જો તે જવાબ અપલિંકનું નામ લે, તો ટનલ ચિત્રમાં નથી અને ટનલની બાજુનું કોઈ સેટિંગ મદદ કરશે નહીં।
અતિથિને ટનલના પોતાના સરનામા પર લાવો
સૌથી નાનો કામ કરતો ફેરફાર એ બહાર જતી વખતે સ્પષ્ટ સ્રોત ફરીથી લખવો છે। તેને ઉમેરવાને બદલે દાખલ કરો: 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 હેન્ડશેક પૂર્ણ થાય છે, પછી મોટું અપલોડ ક્યાંય પણ ભૂલ વિના અટકી જાય છે। મોકલનાર એ જ સેગમેન્ટ કદનું પુનરાવર્તન કરે છે કારણ કે 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 ક્લેમ્પ કરો।
યાદી નીચે ચાલો અને પહેલી નિષ્ફળતા પર થોભો। એ જ સ્તર ઠીક કરવાનું છે; નીચે ઉમેરાયેલી કોઈપણ વસ્તુ ફક્ત તૂટતી સીમાને છુપાવે છે।