درخواست همیشه گونه‌ای از یک جمله است: VPN را برای مرور نگه دار، اما بگذار SSH یا یک کار پشتیبان‌گیری از اتصال عادی استفاده کند. توصیه‌ای که در این باره می‌گردد، یعنی هدایت پورت با قواعد NAT در iptables، این کار را نمی‌کند. یک قاعده NAT نشانی‌ها و پورت‌ها را درون یک جریان بازنویسی می‌کند؛ هرگز انتخاب نمی‌کند که بسته از کدام رابط خارج شود. آن تصمیم به جست‌وجوی مسیر تعلق دارد و جست‌وجوی مسیر برای دیدن پورت به کمک نیاز دارد.

چرا یک مسیر ساده نمی‌تواند با پورت منطبق شود

لینوکس مسیر را با جست‌وجوی نشانی مقصد در یک جدول انتخاب می‌کند، پس از آنکه جدول‌های نامزد با قواعد سیاست فیلتر شدند. آن قواعد می‌توانند با علامت دیوار آتش، نشانی مبدأ، رابط ورودی یا UID منطبق شوند. خودِ ورودی مسیر هیچ فیلد پورتی ندارد، چون مسیر پیش از آنکه سرآیند انتقال اهمیت داشته باشد انتخاب می‌شود.

iproute2 و هسته‌های امروزی انتخابگر قاعده را گسترده‌تر کرده‌اند: ipproto، sport و dport پذیرفته می‌شوند، پس ip rule add ipproto tcp dport 22 table 100 قصد را در یک خط بیان می‌کند. ip rule add help را روی میزبان واقعی اجرا کنید تا ببینید ساخت شما dport را فهرست می‌کند یا نه. اگر می‌کند، با یک فرمان کار تمام است؛ اگر نمی‌کند، مسیر علامت در پایین معادل آن است.

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

سه قطعه، یا یکی

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

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

سه قطعه به ترتیب

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

nft add table inet vpnexempt
nft 'add chain inet vpnexempt out { type route hook output priority mangle; }'
nft add rule inet vpnexempt out tcp dport 22 meta mark set 0x1

دوم، بسته‌های علامت‌خورده را به جدولی جداگانه بفرستید:

ip rule add fwmark 0x1/0x1 table 100

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

ip route add default via 192.168.1.1 dev wlan0 table 100

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

چه چیزی آن را پس از نخستین بسته فعال نگه می‌دارد

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

فیلتر مسیر معکوس قاتل خاموش دیگر است. اگر هسته مسیر بازگشت را سخت‌گیرانه اعتبارسنجی کند و پاسخ روی رابطی برسد که جدول اصلی آن را انتخاب نمی‌کرد، بسته بدون هیچ پیامی دور انداخته می‌شود. rp_filter مقادیر پیش‌فرض بسته به توزیع و بسته به اینکه رابط ارسال می‌شود متفاوت است، پس مقدار مؤثر را بخوانید نه اینکه فرض کنید خاموش است.

انتقال خودِ تونل را علامت نزنید. تونل WireGuard یا UDP OpenVPN پورت TCP 22 نیست، پس دستور بالا ایمن است، اما استثنایی که به‌صورت همه چیز جز مقصد تونل نوشته شود می‌تواند بسته‌های رمزگذاری‌شده را بگیرد و تونل را به شکلی بشکند که شبیه یک حلقه مسیریابی به نظر برسد.

به‌جای فرض‌کردن، بررسی کنید

از هسته بپرسید چه مسیری را می‌پیماید، برای مقصد و برای پورت، سپس انتقال واقعی را اجرا کنید:

ip route get 203.0.113.10
ip rule show
nft list ruleset

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

چه زمانی این ابزار اشتباه است

استثناهای مبتنی بر پورت ذاتاً شکننده‌اند. سرویس‌ها پورت عوض می‌کنند، HTTP/3 به‌صورت UDP 443 می‌آید و یک برنامه می‌تواند چندین جریان از گونه‌های مختلف باز کند. اگر نیاز واقعی این است که این برنامه از پیوند عادی استفاده کند، لایه مسیریابی جای اشتباهی است؛ فضای نام شبکه یا پروکسی برای هر برنامه بهتر می‌نشیند.

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

پیش از دست‌زدن به دیوار آتش بنویسید کدام یک از این سه نیاز را واقعاً دارید. سازوکار بالا دقیق است و دقتی که به لایه اشتباه اعمال شود فقط یک قطعی طولانی‌تر است.

مقالات مرتبط