کسی می‌خواهد مرورگر از تونل استفاده کند و پاسخ به‌صورت قاعده دیوار آتش برمی‌گردد که با پورت‌های مقصد 80 و 443 مطابقت دارد. دقیق به نظر می‌رسد و دقیق نیست. تطبیق پورت بسته‌ها را بر اساس سرآیند انتقال انتخاب می‌کند، نه بر اساس اینکه کدام برنامه سوکت را باز کرده، و مرور مدرن خود را به آن دو پورت روی TCP محدود نمی‌کند. قاعده بخشی از ترافیکی را که می‌خواستید شامل شود از دست می‌دهد و ترافیکی را می‌گیرد که هرگز قصد نداشتید لمس کنید. پیش از نوشتن آن، تصمیم بگیرید کدام‌یک از سه مرز متفاوت را واقعاً می‌خواهید.

قاعده یک کلاس انتقال را توصیف می‌کند، نه یک برنامه

در Linux، تطبیق پورت مقصد سرآیند TCP را بررسی می‌کند و چیزی بالاتر از آن را نه. علامت‌گذاری آن بسته‌ها و هدایتشان با مسیر سیاستی دقیقاً همان‌طور که مستند شده کار می‌کند و هیچ‌یک از این سازوکارها نمی‌داند بار مفید چه معنایی دارد یا کدام فرایند آن را فرستاده است. علامت شماره‌ای است که به بسته چسبیده، نه هویتی که به برنامه چسبیده باشد.

nft add rule inet mangle output tcp dport { 80, 443 } meta mark set 0x1
ip rule add fwmark 0x1 table 100
ip route add default dev wg0 table 100

دو پیامد بی‌درنگ دارد. به‌روزرسان نرم‌افزاری که به TCP 443 متصل می‌شود همان رفتاری را می‌گیرد که مرورگر، که ممکن است خوب باشد یا قطعی باشد که منتظر چرخه به‌روزرسانی بعدی است. و سرویس وبی که عمداً روی پورت دیگری منتشر شده، فرض کنید 8443، کاملاً بیرون از قاعده می‌افتد، هرچند همان ترافیک وبی است که برای کاربر اهمیت داشت.

این اعداد وقتی الزام واقعاً درباره همان پورت‌هاست، انتخاب‌گرهای مشروعی هستند. وقتی در تیکت «مرورگر» نوشته شده و در مجموعه قواعد یک بازه پورت پیاده می‌شود، داستان می‌شوند. این شکاف یک نکته تشریفاتی مستندسازی نیست. تفاوت میان قاعده‌ای است که می‌توانید در یک بازبینی از آن دفاع کنید و قاعده‌ای که هیچ‌کس نمی‌تواند بیازماید.

HTTP/3 بی‌صدا قاعده TCP شما را ترک می‌کند

HTTP/3 روی QUIC کار می‌کند و QUIC در UDP حمل می‌شود. قاعده‌ای که فقط با TCP مطابقت دارد نمی‌تواند آن را ببیند، بنابراین همان مرورگری که صفحه آزمایش شما را برآورده می‌کند می‌تواند درخواست بعدی را از UDP بفرستد و بدون اینکه کسی تنظیمی را عوض کند از تونل بگذرد. RFC 9114 پروتکل HTTP/3 را QUIC-محور توصیف می‌کند و QUIC در استقرار معمول از UDP با پورت پیش‌فرض 443 استفاده می‌کند.

اینکه مرورگر مشخصی HTTP/3 را امتحان می‌کند به پیکربندی آن، به سایت و به موفق بودن تلاش قبلی بستگی دارد. همین آن را چیز بدی برای استدلال از حافظه می‌کند. به‌جایش از ابزار بپرسید:

curl --http3 -sS -o /dev/null -w '%{http_version} %{time_total}\n' https://example.com
ss -tunp | grep -E ':443\b'

خط curl نسخه مذاکره‌شده را چاپ می‌کند، پس 3 تأیید می‌کند که مسیر UDP استفاده شده است. سپس فهرست سوکت‌ها نشان می‌دهد آن اتصال به رابط تونل بسته شده یا به رابط فیزیکی. اگر HTTP/3 در ساخت curl شما موجود نباشد، پرچم بلند شکست می‌خورد نه اینکه بی‌صدا عقب بنشیند، که همان رحم کوچک خودش است.

DNS تصمیمی جداگانه است که باید بگیرید

قاعده پورت برای ترافیک وب هیچ چیزی درباره تجزیه نام نمی‌گوید. مرورگر می‌تواند از تحلیلگر سیستم، تحلیلگری که درون مرورگر پیکربندی شده یا یکی که آخرین اتصال هل داده استفاده کند. هر یک از این‌ها می‌تواند پرس‌وجوها را از مسیری متفاوت از آنچه قاعده شما انتخاب می‌کند بفرستد، که همان شکاف کلاسیک را می‌سازد: صفحه بار می‌شود، نام جایی تجزیه می‌شود که انتظارش را نداشتید و سایت داخلی به نشانی عمومی تجزیه می‌شود یا اصلاً نمی‌شود.

این را صریح تصمیم بگیرید. اگر نام‌های داخلی باید از طریق تونل تجزیه شوند، تحلیلگر باید درون آن باشد و مجموعه قواعد باید DNS به آن تحلیلگر را اجازه دهد و پرس‌وجوهای دیگر را بیرون نگه دارد. اگر مرورگر از DNS over HTTPS به ارائه‌دهنده عمومی استفاده کند، پرس‌وجو کاملاً از تحلیلگر شما عبور می‌کند و قاعده پورت نمی‌تواند کمکی کند. انتخاب را در همان سابقه تغییر قاعده مسیریابی بنویسید، چون هر کسی که خرابی بعدی را اشکال‌زدایی کند هر دو را با هم می‌خواند.

سپس با تحلیلگر بررسی کنید نه با صفحه:

resolvectl query intranet.example.internal
resolvectl status | grep -A3 'Current DNS Server'

پاسخ نبودن یک مشکل تجزیه است حتی وقتی پیام خطای مرورگر شبکه را سرزنش می‌کند. این دو خرابی برای کاربر یکسان به نظر می‌رسند و بلیت‌هایی کاملاً متفاوت‌اند.

سه مرز، سه سازوکار متفاوت

بیشتر سردرگمی وقتی مرزی را که می‌خواهید نام ببرید از بین می‌رود. این‌ها قابل تعویض نیستند و هر یک در هنگام قطع تونل شیوه شکست متفاوتی دارد.

What you actually wantMechanism that fitsWhat it does not cover
These transport ports use this exitFirewall mark plus policy routeApplications, HTTP/3 over UDP, DNS
This browsing session stays separateApplication-aware VPN, or a separate network namespace plus a proxyOther applications in the same session
Only these private sites are reachableDestination-based routes with private DNSPublic sites on the same address family

نمای مرورگر جداگانه دام ردیف میانی است. کوکی‌ها و تاریخچه را جدا می‌کند و هیچ چیزی در جدول مسیریابی میزبان تغییر نمی‌دهد، پس هر دو نما همان مسیر را می‌روند. جداسازی چیزی می‌خواهد که هسته اعمال کند، یعنی فضای نام، کانتینر یا برنامه‌ای که رابط تونل خودش را دارد.

هر ردیفی که باشد، بنویسید وقتی تونل می‌افتد چه باید بشود. مسیر مبتنی بر علامت که با رابط ناپدید می‌شود معمولاً به مسیر پیش‌فرض فیزیکی برمی‌گردد، که رفتار fail-open است. این ممکن است برای مرور قابل قبول و برای هر چیز دیگری غیرقابل قبول باشد، و این یک تصمیم است نه جزئیات پیاده‌سازی.

جریان‌هایی را که ادعا می‌کنید پوشش می‌دهید آزمایش کنید

آزمون پذیرش باید از مرزی که نوشتید پیروی کند، نه از شماره پورت‌هایی که راحت بودند. یک جریان که باید از تونل برود، یکی که نباید، و یکی که از انتقالی استفاده می‌کند که به آن فکر نکرده بودید انتخاب کنید:

ip route get 203.0.113.40
curl -sS -o /dev/null -w 'v4 %{http_version} %{remote_ip}\n' https://example.com
nft list ruleset | grep -A2 'dport'

جست‌وجوی مسیر می‌گوید یک مقصد واقعاً از کدام رابط استفاده می‌کند، و این همان واقعیتی است که بیشتر گزارش‌ها اشتباه می‌گویند. خط curl نسخه مذاکره‌شده و خانواده نشانی را تأیید می‌کند. خروجی مجموعه قواعد قاعده‌ای را می‌گیرد که هنگام آزمون اضافه کردید و محدود کردنش را فراموش کردید، و این‌گونه یک علامت موقت به مسیریابی دائمی fail-open تبدیل می‌شود.

هر سه خروجی را با مهر زمانی ثبت کنید و همراه تغییر نگه دارید. وقتی بعداً کسی گزارش دهد که «VPN شبکه داخلی را خراب کرد»، تفاوت میان مرز موردنظر و مرز پیاده‌شده در همان سابقه دیده می‌شود و اصلاح یک تغییر قاعده خواهد بود نه یک بحث.

مقالات مرتبط