مقالات معمّقة حول التكنولوجيا التي تشكّل المستقبل.

إعدادات DNS ما زالت تُسقط الأنظمة الإنتاجية

يبدو DNS بسيطًا حتى يتعطل. تعرّف على كيف تسبب تحديثات نظام التشغيل وresolv.conf وmDNS ونطاق .internal انقطاعات إنتاجية لا يتوقعها المطورون.

رسائل تُوجَّه بالخطأ إلى أنابيب هوائية خاطئة في غرفة فرز

أطلقت آبل أحدث إصدارات macOS فأفسدت إعدادات DNS المخصصة لآلاف المطورين. فعلى وجه التحديد، بدأ النظام يعترض الاستعلامات الخاصة بنطاق .internal — الذي تستخدمه شركات كثيرة لموارد الشبكة الخاصة — ويحوّلها إلى mDNS (multicast DNS) بدلًا من محلل DNS المُعدّ. خدمات كانت تعمل بسلاسة منذ سنوات صارت فجأة لا يمكن الوصول إليها. الحل لم يكن واضحًا، ورسائل الخطأ لم تكن مفيدة. وكالعادة في مشاكل DNS، بدت الأعراض وكأنها أي شيء إلا DNS.

هذه قصة عن إعدادات DNS — موضوع يصادفه كل مطور، ويفهمه قليلون بعمق، ويستهين به الجميع حتى يعطّل شيئًا في الإنتاج الساعة 2 فجرًا.

حادثة نطاق .internal

كثير من المؤسسات تستخدم .internal كنطاق علوي خاص للخدمات الداخلية: api.internal وdb.staging.internal وgrafana.internal. بدا هذا خيارًا آمنًا: فهو ليس نطاقًا عامًا، ويدل بوضوح على أن الخدمة داخلية، وقد استُخدم بهذا الشكل لعقود.

ثم قررت أنظمة آبل الجديدة أن .internal ينبغي أن يُعالَج عبر mDNS — نفس البروتوكول الذي يحلّ myprinter.local على شبكتك المنزلية. عندما يحاول جهاز Mac الوصول إلى api.internal، فبدلًا من سؤال خادم DNS المُعدّ، يبث استعلام mDNS على الشبكة المحلية. خادم DNS لا يرى الاستعلام أبدًا. والنتيجة إما لا شيء (انتهاء مهلة)، أو عنوان خاطئ (إذا ردّ جهاز ما على الشبكة المحلية على هذا الاسم).

الأعراض: الأمر curl api.internal يتجمّد 5 ثوانٍ ثم يفشل. اتصالات SSH بالمضيفات الداخلية تنتهي مهلتها. مستخدمو VPN لا يصلون إلى الموارد الداخلية. حاويات Docker لا تستطيع حل أسماء الخدمات. ولأن الفشل يظهر كمهلة اتصال عامة، يبدأ معظم المطورين بتتبع الـVPN والجدار الناري والتطبيق نفسه — أي شيء إلا DNS.

كيف يعمل حل DNS فعليًا في الأنظمة الحديثة

نموذج «DNS بسيط» في الذهن — جهازك يسأل خادم DNS عن عنوان IP فيرد الخادم — لم يعد دقيقًا منذ سنوات. الأنظمة الحديثة تملك خط معالجة للحل يضم مراحل متعددة، وكل مرحلة قادرة على اعتراض الاستعلامات أو تعديلها أو إعادة توجيهها.

DNS resolution pipeline on a typical macOS/Linux system:
Application calls getaddrinfo("api.internal")
↓
1. /etc/hosts — checked first. Static overrides.
↓
2. NSSwitch / resolver configuration
- Linux: /etc/nsswitch.conf controls lookup order
- macOS: /etc/resolver/* for per-domain DNS servers
↓
3. System resolver (systemd-resolved, mDNSResponder)
- May intercept .local, .internal, or other special TLDs
- May apply DNSSEC validation
- May cache responses
↓
4. DNS server (from DHCP, VPN, or manual config)
- Queries sent to configured upstream resolver
- May go through a corporate DNS proxy
↓
5. Recursive resolver (8.8.8.8, 1.1.1.1, corporate)
- Walks the DNS hierarchy: root → TLD → authoritative
↓
Response flows back up the chain

وفي كل مرحلة قد يحدث خلل. قد يعترض المحلل في النظام الاستعلام قبل أن يصل إلى خادم DNS المُعدّ. وقد يتجاوز الـVPN إعدادات DNS. وقد يدفع DHCP خوادم DNS تتقدم على إعداداتك اليدوية. والتخزين المؤقت على كل مستوى يعني أن الإصلاح قد لا يسري فورًا.

خرافة /etc/resolv.conf

في Linux، كان الملف /etc/resolv.conf تاريخيًا المصدر الوحيد للحقيقة فيما يخص إعدادات DNS. تضع خادم الأسماء فيه فيستخدمه النظام. بسيط.

لكن توزيعات Linux الحديثة جعلت الأمر أكثر تعقيدًا بكثير. إذا كنت تستخدم systemd-resolved (وهو الافتراضي في Ubuntu وFedora ومعظم توزيعات systemd)، فإن /etc/resolv.conf يصبح رابطًا رمزيًا إلى محلل مختصر على 127.0.0.53. إعدادات DNS الفعلية تعيش في حالة systemd-resolved، وتُدار عبر resolvectl. وتعديل /etc/resolv.conf مباشرة يعني إما أن يُستبدل عند أول تغيير في الشبكة، أو أن يكسر المحلل المختصر.

# What you THINK your DNS config is:
$ cat /etc/resolv.conf
nameserver 127.0.0.53  # This is systemd-resolved's stub
# What your DNS config ACTUALLY is:
$ resolvectl status
Global:
DNS Servers: 8.8.8.8 8.8.4.4
DNS Domain: ~.
Link 2 (eth0):
DNS Servers: 10.0.0.1  # From DHCP — this takes precedence
DNS Domain: corp.internal
Link 5 (wg0):  # WireGuard VPN
DNS Servers: 10.100.0.1
DNS Domain: ~internal  # VPN claims the .internal domain
# Three different DNS servers, each handling different domains.
# /etc/resolv.conf shows none of this.

يضيف Docker طبقة أخرى. حاويات Docker تحصل على /etc/resolv.conf خاص بها، يُنسخ عادةً من إعدادات المضيف عند بدء تشغيل الحاوية. إذا تغيّر DNS المضيف (اتصال VPN أو تبديل شبكة)، تحتفظ الحاويات العاملة بالإعدادات القديمة حتى تُعاد تشغيلها. وهذه مصدر شائع لأخطاء من نوع «يعمل بعد إعادة التشغيل ويفشل بعد مدة».

DNS المقسّم وتعارضات VPN

DNS المقسّم (Split DNS) — أي استخدام خوادم DNS مختلفة لنطاقات مختلفة — شائع جدًا في البيئات المؤسسية. يوجّه الـVPN استعلامات *.corp.internal إلى خادم DNS الشركة، بينما تذهب الاستعلامات العامة إلى المحلل المعتاد. يعمل هذا جيدًا عند ضبطه بشكل صحيح، ويفشل بطرق مربكة عندما لا يكون كذلك.

أنماط الفشل الشائعة:

  • VPN يدفع خوادم DNS كإعدادات افتراضية عامة. بعض عملاء VPN يضبطون خادم DNS الخاص بالشبكة الافتراضية كمحلل رئيسي لكل الاستعلامات، لا للداخلية فقط. فتمر كل استعلامات DNS — بما فيها تصفحك الشخصي — عبر خادم الشركة. وهذا بطيء (لأن خادم الشركة في مركز بيانات آخر) ويثير قضايا خصوصية.
  • تعارض ترتيب خوادم DNS. عند ضبط عدة خوادم DNS، يجربها النظام بالترتيب. إذا كان الأول بطيئًا أو غير قابل للوصول (انقطع الـVPN لكن بقيت إعدادات DNS)، فكل استعلام ينتظر انتهاء المهلة قبل تجربة الثاني. وهذا يضيف تأخيرًا قدره 5 ثوانٍ لكل اتصال.
  • نطاقات البحث تُلحق بصمت. إذا كان نطاق البحث corp.internal، فإن استعلام api يجرب أيضًا api.corp.internal. هذا مفيد (تكتب ssh api بدلًا من ssh api.corp.internal) إلى أن يصبح ضارًا — عندما يتصادم اسم مضيف قصير مع اسم خدمة داخلية، فتُحل الاستعلامات إلى عنوان IP خاطئ.
  • mDNS يعترض النطاقات الداخلية. كما تُظهر حادثة .internal، قد يعترض محلل النظام استعلامات نطاقات معينة قبل وصولها إلى أي خادم DNS مُعدّ. وهذا خطير بشكل خاص لأن الاعتراض يحدث بصمت — لا رسالة خطأ، فقط مهلة أو رد خاطئ.

تشخيص DNS: الأدوات

عندما يتعطل DNS، تحتاج إلى أدوات تُظهر لك بالضبط ما يحدث في كل مرحلة من خط معالجة الحل.

# 1. Check what your system actually resolves:
$ dig api.internal
# Shows: query sent to which server, response received
# The 'SERVER' line tells you which DNS server answered
# 2. Query a specific DNS server directly:
$ dig @10.100.0.1 api.internal
# Bypasses the system resolver — goes directly to the specified server
# If this works but 'dig api.internal' doesn't, the problem is
# in the system resolver, not the DNS server
# 3. Check systemd-resolved state (Linux):
$ resolvectl query api.internal
# Shows which interface/server handled the query
# 4. Check macOS DNS routing:
$ scutil --dns
# Shows per-domain DNS configuration on macOS
# Look for your .internal domain — is it being routed correctly?
# 5. Monitor DNS queries in real time:
$ sudo tcpdump -i any port 53
# See actual DNS packets. If no packets go out for your query,
# the system resolver is intercepting it locally.
# 6. Flush DNS cache (when fixing config):
$ sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder  # macOS
$ resolvectl flush-caches  # Linux with systemd-resolved

أهم خطوة تشخيصية: استعلم من خادم DNS مباشرة باستخدام dig @server hostname. إذا نجح ذلك بينما يفشل الحل العادي، فالمشكلة تقع بين تطبيقك وخادم DNS — اعتراض من محلل النظام أو تخزين مؤقت أو توجيه. وإذا فشلت الاستعلامات المباشرة أيضًا، فالمشكلة في خادم DNS نفسه أو في الاتصال الشبكي به.

اختيار نطاقك الخاص

حادثة .internal تطرح سؤالًا عمليًا: ما النطاق الذي ينبغي استخدامه للخدمات الداخلية؟ لا توجد إجابة آمنة للجميع، لكن بعض الخيارات أفضل من غيرها.

  • .internal — خصّصه RFC 6762 للاستخدام الداخلي، لكن معالجة mDNS من آبل تجعله إشكاليًا على macOS. قد يعمل بشكل جيد على Linux.
  • .local — محجوز لـ mDNS (RFC 6762). استخدامه للخدمات المحلولة عبر DNS سيتعارض مع Bonjour وAvahi. لا تستخدمه.
  • .corp و.home و.mail — غير محجوزة. يمكن لـICANN تخصيصها كنطاقات عامة في أي وقت، فيتعطل حلك الداخلي. لا تستخدمها.
  • نطاق فرعي من نطاق تملكه. internal.yourcompany.com — هذا هو الخيار الأكثر أمانًا. أنت تتحكم في النطاق الأب، فلا خطر من التصادم. العيب: إنه أطول في الكتابة.
  • .test و.example و.invalid و.localhost — محجوزة بموجب RFC 6761 ومضمون ألا تُخصص كنطاقات عامة أبدًا. .test هو الخيار الأنظف للخدمات الداخلية غير الإنتاجية.

الإجابة المملّة لكنها الصحيحة: استخدم نطاقًا فرعيًا من نطاق تملكه. api.internal.yourcompany.com لا لبس فيه، ولن يتصادم مع أي شيء، ويعمل بشكل صحيح على كل نظام وكل محلل DNS. إنه أطول، لكن مشاكل DNS الساعة 2 فجرًا أسوأ بكثير من كتابة بضعة أحرف إضافية.

دروس لأنظمة الإنتاج

كل انقطاع في DNS يعلّم الدروس نفسها، ونحن نعيد تعلمها باستمرار.

  1. راقب حل DNS، لا خوادم DNS فقط. كون خادم DNS سليمًا لا يعني أن الحل يعمل. راقب المسار كاملًا: هل يستطيع تطبيقك فعلًا حل أسماء المضيفات التي يحتاجها؟ فحص اصطناعي يحل أسماء المضيفات الحرجة كل 30 ثانية يكتشف المشاكل أسرع من مراقبة الخوادم وحدها.
  2. اضبط TTL قصيرًا لـDNS الداخلي. عندما تحتاج إلى تغيير سجل DNS داخلي، فإن TTL الطويل يعني بيانات قديمة مخزنة مؤقتًا. قيم TTL بـ60 ثانية للخدمات الداخلية تمنحك تحويلًا سريعًا عند الفشل مع حمل ضئيل على المحللات.
  3. اختبر تحديثات نظام التشغيل مقابل إعداد DNS لديك. عطل .internal أثّر على مستخدمي macOS فقط. اختبر بيئة التطوير بعد التحديثات الكبرى للنظام، فتغييرات حل DNS نادرًا ما تُذكر في ملاحظات الإصدار.
  4. وثّق بنية DNS لديك. أي خوادم DNS تتعامل مع أي نطاقات؟ أين نقاط التقسيم؟ ماذا يحدث عند انقطاع الـVPN؟ هذا التوثيق هو أول ما ستحتاجه أثناء انقطاع، وآخر ما يكتبه أحد.
  5. جهّز خطة بديلة. إذا فشل حل DNS لخدمة داخلية، هل يستطيع تطبيقك استخدام عنوان IP مُدمج في الكود؟ هذا ليس أنيقًا، لكن عنوان IP مُدمج يعمل أفضل من اسم DNS لا يُحل.

DNS من الخدمات الأساسية التي تكون غير مرئية عندما تعمل، وكارثية عندما تتعطل. حادثة .internal تذكير بأن إعدادات DNS أكثر هشاشة مما تبدو — فتحديث واحد لنظام التشغيل قد يغيّر سلوك الحل لملايين المستخدمين. ابنِ أنظمتك على افتراض أن DNS سيتعطل يومًا، فلن تُفاجأ حين يحدث ذلك.