لماذا تُحل أسماء المضيفين الداخلية في dig وتفشل في curl على VPN
يجيب dig، لكن curl يبلّغ أنه لا يستطيع حل المضيف. قارن سلسلتي البحث، ثم أصلح nsswitch أو DNS لكل رابط أو لاحقة بحث خاطئة.
حاسوبك المحمول متصل بالـ VPN، ويجيب dig service.internal.example بعنوان 10.x، ومع ذلك يخرج curl بالخطأ Could not resolve host. النفق ليس المشكلة: فقد نقل استعلام dig دون اعتراض. الاختلاف في من يطرح السؤال. يرسل dig استعلامًا واحدًا إلى خادم واحد تسمّيه أنت، بينما يمر curl عبر سلسلة البحث في نظام التشغيل، ولهذه السلسلة قواعدها الخاصة بشأن الخادم الذي يُسأل.
بحثان للاسم نفسه
dig هو محلّل stub خاص به. يقرأ /etc/resolv.conf، ويختار خادم أسماء، ويرسل استعلام A أو AAAA واحدًا، ويطبع الرد. يتخطى nsswitch كليًا ولا يعرف شيئًا عن الحالة الخاصة بكل رابط التي يحتفظ بها systemd-resolved أو NetworkManager خارج ذلك الملف، ولهذا يمكن أن يكون رد dig صحيحًا ولا يخبرك شيئًا عمّا ستراه تطبيقك.
تستدعي التطبيقات getaddrinfo، ويمرّ getaddrinfo بسلسلة أطول: ترتيب وحدات nsswitch، ثم الوحدة التي تتعامل مع الاسم، ثم المحلّل المبني من إعدادات الرابط الحالية. على جهاز systemd يذهب الاستعلام إلى 127.0.0.53، ويختار systemd-resolved خادمًا أعلى لكل رابط وفق نطاق التوجيه المرتبط بواجهة tun.
يفصل أمران هاتين الطبقتين دون تخمين:
getent ahosts service.internal.example
resolvectl query service.internal.example
يستخدم getent المسار نفسه الذي يستخدمه curl، لذا فإن فشل getent إلى جانب dig عامل يحدّد العطل في سياسة البحث لا في توجيه الحزم. ويطبع resolvectl query أيضًا الواجهة والخادم الأعلى الذي قدّم الرد، وهذا يبيّن هل فاز قرار رابط النفق أم الرابط الفيزيائي.
اقرأ المحلّل الذي يستخدمه التطبيق فعلًا
يُولَّد /etc/resolv.conf على معظم أسطح المكتب، ولعميل VPN ثلاث طرق للتعامل معه: أن يضيف خادم أسماء في المقدمة، أو أن يكتب فوق الملف، أو أن يسلّم خوادمه إلى NetworkManager ويترك الخدمة تعيد كتابته. النمط الثالث وحده يحافظ على DNS لكل رابط، لأن الخوادم تبقى مرتبطة بواجهة بدل أن تُسطَّح في قائمة عالمية واحدة.
على أنظمة NetworkManager تعتمد النتيجة على الخلفية في /etc/NetworkManager/NetworkManager.conf:
[main]
dns=systemd-resolved
مع dns=default تُدمج خوادم العميل في resolv.conf بالترتيب الذي يفوز، وقد يُرسل استعلام خاص إلى المحلّل العام رغم ذلك. ومع خلفية تفهم الروابط، systemd-resolved أو dnsmasq، تبقى خوادم النفق محصورة في النفق، ولا يذهب إليها إلا الأسماء المطابقة لنطاق توجيهه. هذا الحصر هو ما يعنيه split DNS عمليًا، وهو الجزء الذي يغيب في أغلب الأحيان حين يدّعي عميل أنه يدعمه.
اقرأ الحالة قبل أن تغيّر أي شيء:
resolvectl status
resolvectl dns tun0
تريد أن ترى واجهة tun مدرجة مع خادم DNS ونطاق توجيه لللاحقة الخاصة، معروضًا بالشكل ~internal.example. لا خادم على الرابط يعني أن العميل لم يدفع شيئًا. وخادم بلا نطاق يعني أن الاستعلامات إما تذهب كلها إليه أو لا يذهب أي منها، حسب العميل، وكلا الحالتين ليست split DNS.
حيث ينهي nsswitch البحث مبكرًا
يبدو السطر القياسي على سطح المكتب هكذا:
hosts: files mdns4_minimal [NOTFOUND=return] resolve [!UNAVAIL=return] dns myhostname
يتولى mdns4_minimal بروتوكول DNS المتعدد ويطالب بكل اسم ينتهي بـ .local. وخدمة Kubernetes مثل api.infra.svc.cluster.local تنتهي أيضًا بـ .local. وعندما تبلّغ وحدة mDNS بحالة NOTFOUND، ينهي الإجراء [NOTFOUND=return] البحث كله بدل المتابعة إلى وحدة dns، فلا يُرسل الاسم أبدًا إلى محلّل الـ VPN. يتجاوز dig الملف كليًا، ولهذا تحديدًا يختلف الأداةان.
هذا هو أشد تباين في هذه المشكلة، وهو يعود إلى كلمة واحدة في ملف إعدادات أقدم من الـ VPN لديك. تغيير الإجراء إلى [NOTFOUND=continue] يحافظ على mDNS للطابعات والأجهزة المحلية مع السماح لـ DNS برؤية الاسم. واستبدال السطر بـ hosts: files dns يعمل أيضًا وهو أكثر فظاظة: يُسقط حل .local للطابعة التي تستخدمها فعلًا.
أسماء تعيش في شبكة واحدة فقط
المناطق الخاصة سلطوية في مكان واحد فقط. الاسم في AWS مثل ip-10-0-4-31.eu-west-1.compute.internal يُجاب عنه عبر محلّل VPC لذلك النطاق، وفقط ما دام طرف الـ VPN لديك في النطاق نفسه الذي فيه المورد. اتصل بطرف في فرانكفورت واسأل عن اسم compute.internal من أيرلندا، ولن تساعد أي إعدادات محلية: المنطقة التي تحمل السجل غير قابلة للوصول من هناك.
تنتج نطاقات البحث الصورة المعكوسة. الاسم المجرد service يُكمل باللاحقة التي يراها المحلّل منطبقة، ومع رابط VPN قد يتغلب النطاق المحلي على نطاق الشركة. اسأل بنقطة في النهاية لإزالة التخمين، getent ahosts service.internal.example.، وإذا نجح ذلك بينما يفشل الاسم القصير، فالعلاج هو نطاق البحث على النفق، لا عنوان الخادم.
يضيف العملاء المُدارون طبقة ثالثة فوق محلّل النظام. يمكن لملف تعريف VPN في Windows أن يحمل سياسة حل أسماء خاصة به، وقواعد لكل تطبيق، وجدول NRPT يسري حتى عندما يكون النفق متوقفًا. والتطبيقات التي تملك ذاكرة DNS خاصة بها، وهي شائعة في بيئات .NET وJava، تحتفظ بالفشل القديم طويلًا بعد إصلاح السلسلة. ويضبط عملاء Apple خاصية split DNS عبر نطاقات المطابقة في إعدادات DNS بدل resolv.conf، وقد يتجاوز Chromium أو Firefox في وضع DNS الآمن محلّل النظام للأسماء العامة. ويصف مرجع Microsoft لحل أسماء VPN الجانب الخاص بـ Windows من طبقة السياسة تلك.
قرّر أي طبقة تُصلح
انتقل من العَرَض إلى الطبقة بدل تجربة الإصلاحات بالترتيب:
| Symptom | What it means | Check first |
|---|---|---|
| dig answers, getent fails | lookup chain, not the packet path | nsswitch line and resolvectl status |
| Timeout rather than NXDOMAIN | private resolver unreachable through the tunnel | resolvectl dns tun0, route to that address |
| NXDOMAIN | an authority answered and does not know the name | zone owner, endpoint region |
| FQDN works, short name fails | search suffix mismatch | resolvectl domain on the tun link |
| getent works, app fails | app cache or its own resolver | restart the app, check secure DNS |
صفّان يحملان معظم الثقل. انتهاء المهلة مشكلة وصول: المحلّل الخاص لا يجيب عبر النفق، لذا تحقق من المسار إلى عنوانه ومن أن خادم DNS على الرابط هو الذي تظنه. أما NXDOMAIN فمشكلة سلطة: شيء ما أجاب ولا يعرف الاسم، ما يشير إلى المنطقة أو النطاق أو محلّل لم يكن ينبغي أن يتلقى الاستعلام أصلًا.
الصف الأخير هو الذي يفوته الناس لأن كلا النصفين يبدو نجاحًا. الاسم القصير الذي يُحل بطريقة مختلفة عن FQDN هو عدم تطابق في اللاحقة، وإعادة توصيل النفق لن تغيّر اللاحقة التي يدفعها العميل.
سجّل الحالة قبل أن تحرّر ملف إعدادات، حتى تستطيع أن تقول هل فعل التحرير شيئًا:
resolvectl status > before.txt
getent ahosts service.internal.example >> before.txt
نفّذ الفحوص بهذا الترتيب وتوقف عند أول فشل. يجب أن يتفق getent وresolvectl query؛ وإذا فشل getent بينما يجيب dig فابقَ في سلسلة البحث ولا تلمس التوجيه. ويجب أن يُظهر resolvectl status خادم DNS ونطاق توجيه على واجهة tun. ولا يجوز أن يعود nsswitch مبكرًا بحالة NOTFOUND لللاحقة التي تختبرها. ويجب أن يكون الاسم سلطويًا في الشبكة التي يتصل بها طرفك، مختبرًا بنقطة في النهاية. ولا يجوز أن يحتفظ التطبيق بذاكره الخاصة أو بتجاوز DNS آمن.
أصلح أول طبقة فاشلة فقط، ثم أعد تنفيذ الأوامر نفسها. تغييران في وقت واحد يتركانك عاجزًا عن القول أيهما كان له أثر، ويبدأ العطل التالي التحقيق من الصفر.