اس بہار میں نے ایک صبح کا بڑا حصہ ایسے کنٹینر کے پیچھے لگا کر گزارا جو ایک بھی اندرونی نام حل نہیں کر سکتا تھا، جبکہ ساتھ والا براؤزر بغیر کسی شکایت کے ویکی کھول رہا تھا۔ ٹنل قائم تھا، براؤزر اس کا ثبوت دے رہا تھا، اور کنٹینر کسی دوسرے نیٹ ورک نام کی جگہ میں تھا جس کا راستہ جدول اور حل کنندہ الگ تھا. آگے وہ ترتیب ہے جو میں اب جانچتا ہوں: پہلے راستہ جدول، دوسرا نام کا حل، تیسرا فارورڈنگ اور آخر میں میزبان پلیٹ فارم۔ پہلے ہی ناکام ہونے والے قدم پر رکیں، کیونکہ اسٹیک میں نیچے قواعد شامل کرنا حد کو ہٹانے کے بجائے چھپاتا ہے۔

کوئی قاعدہ بدلنے سے پہلے تینوں راستہ جدول کا موازنہ کریں

Docker کے طے شدہ پل پر موجود کنٹینر کا docker0 گیٹ وے کی طرف ایک ہی طے شدہ راستہ ہے اور اسے معلوم نہیں کہ tun0 موجود ہے۔ میزبان کے پاس tun0، VPN کی دھکیلی ہوئی راستے، اور ممکنہ طور پر ایک پالیسی قاعدہ ہے جو آزمائشی ٹریفک کو توقع سے مختلف انٹرفیس سے باہر بھیجتا ہے۔ WSL اپنے مجازی اڈاپٹر کے پیچھے تیسرا جدول شامل کرتا ہے۔ کسی ایک میں ترمیم سے پہلے تینوں چھاپیں۔

ContextCommandWhat a wrong answer looks like
Hostip route get 10.8.0.20Leaves a physical interface instead of tun0
Containerip routeOnly 172.17.0.0/16 via 172.17.0.1
Container DNScat /etc/resolv.confA public resolver, or an upstream the tunnel never pushed
WSLip addr; ip routeOnly the WSL subnet, no Windows VPN adapter

اگر کنٹینر کا واحد راستہ پل ہے اور tun0 اس کی نام کی جگہ میں کبھی ظاہر نہیں ہوتا، تو نیچے کا کچھ بھی مدد نہیں کرے گا: کوئی نام سرور تبدیلی راستہ نہیں بناتی، اور کوئی راستہ ایسی ٹنل شناخت نہیں بناتا جسے ساتھی قبول کرے۔ ترتیب اہم ہے کیونکہ شیل کے اندر سے DNS کی ناکامی اور راستے کی ناکامی ایک جیسی دکھتی ہیں۔

حل کنندہ کو عام کی طرف نہیں، ٹنل کی طرف موڑیں

میزبان پر، resolvectl status ہر لنک کے لیے DNS سرور فہرست کرتا ہے، اور readlink -f /etc/resolv.conf بتاتا ہے کہ فائل systemd اسٹب ہے، NetworkManager فائل ہے، یا کوئی ایسی چیز جسے وینڈر کلائنٹ نے دوبارہ لکھا۔ صارف کی متعین نیٹ ورک پر کنٹینر کے اندر، /etc/resolv.conf نام دیتا ہے 127.0.0.11, Docker کے اندرونی حل کنندہ کو، جو اس upstream کی طرف فارورڈ کرتا ہے جس کے ساتھ ڈیمن ترتیب دیا گیا تھا۔ البتہ طے شدہ پل کا کنٹینر بننے کے وقت میزبان فائل کی نقل لے چکا تھا اور اسے رکھتا ہے۔

وہی نقل وجہ ہے کہ کنٹینر کے شروع ہونے کے بعد اٹھنے والی ٹنل کنٹینر کو پرانے upstream سے پوچھتا چھوڑ دیتی ہے۔ یا تو VPN حل کنندہ واضح طور پر اس کے ساتھ بھیجیں docker run --dns 10.8.0.53, یا "dns": ["10.8.0.53"] میں /etc/docker/daemon.json مقرر کر کے ڈیمن دوبارہ شروع کریں، یا ٹنل کے قائم ہونے پر کنٹینر دوبارہ بنائیں۔ دوبارہ بنانا عام طور پر ایک گھنٹہ پہلے درست رہنے والے حل کنندہ کو ڈیبگ کرنے سے سستا ہے۔

عام حل کنندہ لگانا وہ مرمت ہے جو علامت کو برقرار رکھتی ہے۔ یہ انٹرنیٹ حل کرتا ہے مگر ہر نجی زون میں ناکام ہوتا ہے، اور اس فلٹرنگ کو خاموشی سے نظرانداز کر سکتا ہے جس کے لیے ٹنل موجود ہے۔ اگر آپ چلتے کنٹینر کے /etc/resolv.conf کے اندر لکھنے کی کوشش کریں تو توقع رکھیں Device or resource busy: Docker اس فائل کو bind-mount کرتا ہے، اس لیے ترمیم کے لیے پہلے ان ماؤنٹ ضروری ہے۔ --dns کو بناتے وقت مقرر کرنا وہ ترتیب ہے جو دوبارہ آغاز پر قائم رہتی ہے۔

جب کنٹینر ٹنل ادھار لیتے ہیں تو فارورڈ کریں اور ترجمہ کریں

طے شدہ پل کے ساتھ، میزبان docker0 اور tun0 کے درمیان روٹر ہے، اور طے شدہ طور پر یہ دونوں کام نہیں کرتا۔ فارورڈنگ آن کریں اور ماخذ پتہ ترجمہ کریں تاکہ ساتھی کو واپسی راستے کے بغیر پتے کے بجائے میزبان کا ٹنل پتہ نظر آئے (tun0 کو اس نام سے بدلیں جو آپ کا کلائنٹ انٹرفیس کو دیتا ہے):

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE
iptables -A FORWARD -i docker0 -o tun0 -j ACCEPT
iptables -A FORWARD -i tun0 -o docker0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

FORWARD قواعد ان میزبانوں پر اہم ہیں جن کی فارورڈ پالیسی DROP ہے۔ Docker اپنی زنجیریں داخل کرتا ہے، اس لیے پڑھنے کے بجائے پیکٹ سے جانچیں iptables -S: کنٹینر سے، ip route get 10.8.0.20 کو پل گیٹ وے کا نام دینا چاہیے، اور nc -vz 10.8.0.20 443 کو حل کنندہ پر نہیں بلکہ ٹنل پر جڑنا یا وقت ختم ہونا چاہیے۔

MASQUERADE کے بغیر ساتھی کو 172.17.0.0/16 تک واپسی راستہ چاہیے، جو زیادہ تر ریموٹ رسائی VPN نہیں دھکیلتے۔ یہیں پالیسی پر مبنی کلائنٹ بھی منصوبہ توڑتا ہے: اگر یہ صرف مخصوص UID یا cgroups کی ٹریفک پکڑتا ہے، تو آپ کے فارورڈ قواعد ٹنل کے اندر پیکٹ کبھی نہیں دیکھتے، اور اصلاح iptables میں نہیں بلکہ کلائنٹ کی روٹنگ پالیسی میں ہے۔ ہاتھ سے شامل کیے گئے قواعد ری بوٹ پر غائب ہو جاتے ہیں، اس لیے انہیں systemd یونٹ یا netfilter-persistent جدول میں رکھیں اور ری بوٹ کے بعد دوبارہ جانچیں، کیونکہ دیر سے اٹھنے والی ٹنل انہیں بہا سکتی ہے۔

جب مقصد علیحدگی ہو تو ٹنل کنٹینر کے اندر رکھیں

اگر ایک کنٹینر کو مخصوص نوڈ سے باہر جانا ہے، تو کلائنٹ اسی کنٹینر میں چلائیں. اسے --cap-add NET_ADMIN اور --device /dev/net/tun درکار ہیں، اور پھر اس کا اپنا tun0، راستے اور فائر وال ہوتا ہے۔ اگر دوسرے کنٹینر اس کے ذریعے گزریں، تو اسے کنٹینر کے اندر فارورڈنگ اور MASQUERADE قاعدہ بھی درکار ہے، اور ان ساتھیوں کو اس کی طرف اشارہ کرنے والا واضح راستہ یا پراکسی چاہیے؛ Docker کا طے شدہ پل وہ راستہ آپ کے لیے شامل نہیں کرتا۔

میزبان نیٹ ورکنگ، docker run --network host, سستا نسخہ ہے: کنٹینر میزبان کی نام کی جگہ میں شامل ہوتا ہے اور ٹنل کے راستے براہ راست دیکھتا ہے۔ یہ نیٹ ورک علیحدگی بھی چھوڑ دیتا ہے، پورٹ ٹکراؤ کو دعوت دیتا ہے، اور عملاً یہ Linux آپشن ہے۔ شائع شدہ پورٹ اس کا متبادل نہیں۔ -p 8080:80 کسی سروس کو میزبان سے قابل رسائی بناتا ہے؛ اندرونی 10.x پتوں کو کنٹینر کے اندر سے قابل رسائی نہیں بناتا، اور دونوں کو ملانا ہی وہ راستہ ہے جس سے روٹنگ مسئلہ کھلا ڈیٹا بیس پورٹ بن جاتا ہے۔

نام کی ناکامی کو اوور لیپنگ سب نیٹ سے الگ کریں

Docker کا طے شدہ پل 172.17.0.0/16 ہے، اور بہت سے کارپوریٹ VPN تالاب 172.16.0.0/12 کے اندر ہیں۔ جب ٹنل اس حد کی مالک ہو جاتی ہے تو کنٹینر کے لیے بھیجی گئی ٹریفک اس کے بجائے ٹنل میں روٹ ہو سکتی ہے۔ نام ناکام ہوتے ہیں، خرابی DNS جیسی دکھتی ہے، اور مسئلہ پتوں میں ہے۔ منزل جانچیں، حل کنندہ نہیں: ip route get 172.17.0.5 میزبان پر، پھر پل کے سابقے کا VPN تالاب اور docker network inspect bridge --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}' سے موازنہ کریں۔

مرمت یہ ہے کہ حدوں میں سے ایک کو ہٹایا جائے: یا daemon.json میں Docker کے لیے دوسرا طے شدہ پتہ تالاب، یا کنسنٹریٹر پر دوسرا تالاب۔ یہاں ایک اور نام سرور شامل کرنا کچھ نہیں کرتا، اور ssh -b بھی نہیں: کلائنٹ کو انٹرفیس سے باندھنا ماخذ پتہ بدلتا ہے، ٹنل کی طرف اشارہ کرنے والا منزل راستہ نہیں۔ فوری کام کی تقسیم: میزبان پر حل ہونے والا مگر کنٹینر میں نہ ہونے والا نام حل کنندہ کا مسئلہ ہے، جبکہ کنٹینر میں اٹکنے والا مگر میزبان پر چلنے والا براہ راست IP رابطہ راستے یا فارورڈ زنجیر کا مسئلہ ہے۔

WSL اور Docker Desktop Linux کے قواعد نہیں مانتے

اپنے طے شدہ NAT موڈ میں، WSL اپنے مجازی اڈاپٹر کے پیچھے بیٹھتا ہے اور Windows VPN کے اندرونی راستے یا DNS لاحقے نہیں پاتا، اسی لیے براؤزر چلتا ہے اور ping تقسیم کے اندر نہیں۔ حالیہ Windows 11 بلڈز میں دستیاب آئینہ نیٹ ورکنگ اس کے بجائے میزبان کے انٹرفیس بانٹتی ہے، مگر اسے .wslconfig میں فعال کرنا اور تقسیم کو wsl --shutdown سے دوبارہ شروع کرنا ضروری ہے۔ فعال موڈ کی تصدیق wslinfo --networking-mode سے کریں، اصلاح لگانے سے پہلے، کیونکہ NAT کا جواب آئینہ موڈ کے لیے غلط ہے اور اس کے برعکس بھی۔

Docker Desktop ایک اور تہہ شامل کرتا ہے۔ Windows پر Linux کنٹینر تاریخی طور پر vpnkit کہلانے والے NAT نفاذ کے پیچھے بیٹھتے ہیں، اور ان کا راستہ مقامی Linux میزبان سے مختلف ہے۔ Windows کنٹینر Hyper-V مجازی سوئچ کے ذریعے جڑتے ہیں، اور کارپوریٹ کلائنٹ اس سوئچ سے آنے والی ٹریفک بلاک کر سکتا ہے، اس لیے ایک ہی مشین پر Linux کنٹینر نیٹ ورک تک پہنچ سکتے ہیں جبکہ Windows کنٹینر کے پاس کچھ نہیں ہوتا۔ جسمانی اڈاپٹر سے بندھا بیرونی سوئچ عام حل ہے، اور یہ کنٹینر کی نیٹ ورک شناخت ایسے طریقوں سے بدلتا ہے جن کی پالیسی اجازت نہ دے۔

ایک اور قاعدہ لکھنے سے پہلے چاروں تہیں ترتیب سے چلیں اور جہاں کوئی ایک غلط ہو وہیں رکیں:

  • کنٹینر کے اندر: کیا ip route نجی سابقے تک پہنچتا ہے، اور کیا /etc/resolv.conf اسے حل کرنے والے upstream کا نام دیتا ہے؟
  • میزبان پر: کیا فارورڈنگ آن ہے، کیا NAT ٹنل انٹرفیس سے بندھا ہے، اور کیا فارورڈ زنجیر پل سے ٹنل قبول کرتی ہے؟
  • ساتھی پر: کیا اسے واپسی راستہ معلوم ہے، یا آپ کنٹینر سب نیٹ چھپانے کے لیے NAT پر بھروسا کرتے ہیں؟
  • پلیٹ فارم پر: WSL NAT یا آئینہ موڈ میں ہے، اور کنٹینر Linux ہے یا Windows؟

ہر جانچ نئے کنٹینر یا شیل میں دوبارہ چلائیں۔ کیش شدہ جواب یا قائم شدہ رابطہ رکھنے والا طویل عمل ترتیب درست ہونے کے بعد بھی ناکام رہے گا، اور وہ ناکامی ایسی مرمت جیسی دکھتی ہے جو کام نہ کر سکی۔

متعلقہ مضامین