عیبیابی شبکه از نام تا پاسخ برنامه
در این درس ۲ بخش
سناریو: مرورگر پیام «سایت باز نمیشود» میدهد. مشکل میتواند از نام دامنه، مسیر، محل گوشدادن سرویس، TCP، TLS یا HTTP باشد. آزمایش فقط روی سرویس موقت خودتان در 127.0.0.1 انجام میشود؛ نیازی به اسکن دیگران یا دسترسی مدیریتی ندارد. نتیجه را همراه ساعت و مقصد دقیق ثبت کنید.
ابتدا یک سرویس با مرز روشن بساز
در ترمینال اول پوشهای اختصاصی با یک فایل بیخطر بسازید. پورت صفر از سیستمعامل درخواست یک پورت آزاد میکند؛ عدد واقعی را از پیام آغاز سرور بردارید. آدرس 127.0.0.1 فقط loopback همین محیط است، پس رایانه یا گوشی دیگر نمیتواند با IP شبکه به آن دسترسی پیدا کند. پوشهٔ خانه یا پروژهٔ دارای راز را سرو نکنید؛ http.server برای این آزمایش محلی است و برای استقرار سرویس عمومی طراحی نشده است.
net_lab=$(mktemp -d)
printf 'local-ok\n' > "$net_lab/index.html"
python3 -m http.server 0 --bind 127.0.0.1 --directory "$net_lab"در ترمینال دوم پورت اعلامشده را وارد کنید. ss با l سوکتهای گوشدهنده، با t TCP و با n شمارههای عددی را نشان میدهد. فیلتر فقط پورت همین آزمایش را بررسی میکند. curl با نشانی عددی، تبدیل نام را کنار میگذارد؛ --noproxy مانع ارسال درخواست محلی از مسیر پراکسی میشود. گزینهٔ -q باید اول بیاید تا تنظیمات شخصی curl نتیجه را تغییر ندهند.
read -r -p 'Local server port: ' net_port
ss -ltnp "sport = :$net_port"
curl -q --noproxy '*' --connect-timeout 2 --max-time 5 \
-sS -o /dev/null -w 'HTTP=%{http_code}\n' \
"http://127.0.0.1:$net_port/"
curl -q --noproxy '*' --connect-timeout 2 --max-time 5 \
-sS -o /dev/null -w 'HTTP=%{http_code}\n' \
"http://127.0.0.1:$net_port/missing"برای فایل موجود انتظار HTTP=200 و برای مسیر ناموجود انتظار HTTP=404 داریم. هر دو نشان میدهند اتصال برقرار و یک پاسخ HTTP دریافت شده است؛ curl بدون گزینهٔ fail ممکن است برای 404 هم با کد خروج صفر تمام شود. خطای اتصال، کد خروج برنامه و وضعیت HTTP سه چیز جدا هستند. connect-timeout مرحلهٔ برقراری اتصال، شامل حل نام و handshake لازم، را محدود میکند؛ max-time سقف کل انتقال است. این سرور HTTP ساده TLS ندارد؛ تغییر دلخواه نشانی آن به https آزمون معتبر گواهی نمیسازد.
لایهٔ شکست را جدا کن
برای سرویس مجاز واقعی ابتدا بررسی کنید نام به مقصد موردنظر تبدیل میشود یا نه؛ getent ahosts نامِ خودتان مسیر حل نام سیستم را میآزماید و ممکن است علاوه بر DNS از /etc/hosts استفاده کند. سپس نشانی شنونده را بسنجید: 127.0.0.1 با 0.0.0.0 یا [::] یکسان نیست و رفتار IPv6 را نباید از IPv4 حدس زد. دستور خواندنی ip route get برای مقصد مشخص، مسیر انتخابی کرنل را بررسی میکند و بستهای به آن مقصد نمیفرستد. موفقیت این بررسی، دسترسی انتهابهانتها را ثابت نمیکند.
وجود مسیر محلی تضمین نمیکند مسیر برگشت یا NAT در روتر درست باشد. NAT نشانی یا پورت را ترجمه میکند و بهخودیخود سرویس را راه نمیاندازد. سرویس گوشدهنده نیز اثبات عبور از فایروال یا روتر نیست. «Connection refused» معمولاً رد فعال اتصال در مسیر یا مقصد را نشان میدهد؛ timeout میتواند از حذف بسته، مسیر معیوب یا پاسخندادن ناشی شود. بدون شاهد اضافه، هر timeout را فایروال ننامید. موفقیت ping هم بهتنهایی بازبودن TCP یا سلامت برنامه را تأیید نمیکند.
بعد از TCP، در HTTPS باید نام میزبان، زنجیرهٔ اعتماد گواهی و ساعت سیستم درست باشند. گواهی نام دامنه لزوماً برای IP مستقیم معتبر نیست. بررسی گواهی را خاموش نکنید؛ در محیط دارای CA خصوصی، گواهی CA تأییدشده را برای همان درخواست با --cacert معرفی میکنند. سپس وضعیت HTTP و رفتار برنامه را بررسی کنید: 401، 403 و 500 پاسخ برنامهاند، نه شاهد قطع DNS. هنگام ثبت خطا، هدر Authorization، کوکی یا نشانی دارای توکن را منتشر نکنید.
دید ابزار هم محدود است. ss -p برای نمایش نام و PID همهٔ پردازشها به مجوز و تنظیمات محیط وابسته است. در کانتینر ممکن است هشدار Netlink ببینید یا فقط بخشی از سوکتها نمایش داده شوند؛ خروجی خالی اثبات نبود سرویس نیست. اگر ip route مجوز نداشت، محدودیت را ثبت کنید. پایان تمرین، سرور ترمینال اول را با Ctrl+C متوقف کنید و فقط فایل و پوشهٔ اختصاصی همین آزمایش را پاک کنید.
تمرین و پاسخ: اگر درخواست اول 200 و دومی 404 شد ولی گوشی شما وصل نشد، محتملترین توضیح چیست؟ فایل ناموجود علت 404 است؛ دریافت آن سلامت همهٔ اجزای اینترنت را ثابت نمیکند. شکست گوشی با bind روی loopback سازگار است و برای حل تمرین لازم نیست سرور را عمومی کنید. اگر ss هشدار مجوز داد ولی curl محلی 200 گرفت، شاهد مستقیم HTTP را نگه دارید و محدودیت مشاهدهٔ سوکت را صریح گزارش کنید.
منابع رسمی انگلیسی:
Python: https://docs.python.org/3.12/library/http.server.html
curl: https://curl.se/docs/manpage.html
TLS: https://curl.se/docs/sslcerts.html
ss: https://man7.org/linux/man-pages/man8/ss.8.html
ip-route: https://man7.org/linux/man-pages/man8/ip-route.8.html
getent: https://www.man7.org/linux/man-pages/man1/getent.1.html
NAT: https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)
تألیف و مثالهای اختصاصی: تحریریه درسآوند. منابع رسمی انگلیسی برای مطالعهٔ تکمیلی معرفی شدهاند.
متن درسهای عمومی را بدون ورود بخوانید.