صرف 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 کلیمپ کریں۔
فہرست میں نیچے چلیں اور پہلی ناکامی پر رکیں۔ وہی پرت درست کرنی ہے؛ نیچے شامل کی گئی کوئی بھی چیز صرف ٹوٹتی سرحد چھپاتی ہے۔