نمی‌توانید یک برنامه را با ویرایش مسیرها از میزبان WireGuard با تونل کامل مستثنی کنید. مسیرها راه را بر اساس مقصد انتخاب می‌کنند، و آنچه می‌خواهید مستثنی کنید یک فرایند است، بنابراین هسته چیزی برای تطبیق ندارد. رویکرد عملی این است که به آن فرایند زمینه شبکه خودش را بدهید: یک فضای نام با رابط، نشانی‌ها و مسیر پیش‌فرض خودش که با یک جفت veth به میزبان متصل است. این را روی Ubuntu 24.04 با wireguard-tools 1.0.20210914 اجرا کردم، و فضای نام هرگز مشکل نبود — سیاست ارسال میزبان و قواعد علامت‌گذاری تونل مشکل بودند.

ابتدا نوع زمینه‌ای را که لازم دارید انتخاب کنید

در عمل دو شکل دیده می‌شود. اگر میزبان یک تونل کامل اجرا می‌کند و یک برنامه باید از مسیر ISP خارج شود، فضای نام دومی می‌سازید، آن را به میزبان متصل می‌کنید و می‌گذارید میزبان ترافیک را برایش ارسال و ترجمه کند. اگر فضای نامی از قبل یک رابط VPN دارد و فقط به فرمانی نیاز دارید که درون آن اجرا شود، این همان حالت معمول ip netns exec است و بیشتر کار مسیریابی انجام شده است.

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

اگر الزام واقعاً این است که چیزی از تونل بیرون نرود، به جایش تونل را متوقف کنید. فضای نام برای حالت مختلط وجود دارد: یک برنامه بیرون، بقیه چیزها درون، روی همان ماشین، در همان زمان.

زمینه دوم را بسازید و آن را به میزبان متصل کنید

یک چیدمان نمونه: میزبان یک رابط WireGuard دارد که مسیر پیش‌فرض را حمل می‌کند، و یک فضای نام شبکه به نام clearnet که با یک جفت veth به میزبان متصل است. نشانی‌های زیر نمونه‌اند.

ip netns add clearnet
ip link add veth-clear-out type veth peer name veth-clear-in
ip addr add 192.168.100.1/24 dev veth-clear-out
ip link set veth-clear-out up
ip link set veth-clear-in netns clearnet
ip netns exec clearnet ip addr add 192.168.100.2/24 dev veth-clear-in
ip netns exec clearnet ip link set veth-clear-in up
ip netns exec clearnet ip route add default via 192.168.100.1

این فضای نام اکنون می‌تواند به میزبان برسد و به هیچ چیز دیگری. میزبان باید ترافیک را ارسال کند و نشانی مبدأ را بازنویسی کند، زیرا 192.168.100.0/24 خصوصی است و مسیریاب بالادست مسیری برای بازگشت به آن ندارد:

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o <wan-interface> -j MASQUERADE

پیش از ادامه، سمت فضای نام را تأیید کنید.ip netns exec clearnet ip route باید مسیر veth و مسیر پیش‌فرض از طریق 192.168.100.1 را نشان دهد، و ping به آن نشانی باید پاسخ دهد. اگر ping به نشانی میزبان شکست بخورد، نشانی‌ها یا وضعیت پیوند اشتباه است و هیچ قاعده فایروالی کمکی نمی‌کند.

وقتی نام‌ها حل می‌شوند اما چیزی برنمی‌گردد، FORWARD را بخوانید

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

پیش از افزودن هر چیزی، زنجیره را بخوانید:

iptables -S FORWARD
nft list chain inet filter forward

سپس ترافیک را در هر دو جهت با شمارنده‌ها مجاز کنید تا بتوانید بفهمید آیا قاعده هرگز مطابقت کرده است:

iptables -A FORWARD -i veth-clear-out -o <wan-interface> -j ACCEPT
iptables -A FORWARD -i <wan-interface> -o veth-clear-out -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
watch -n1 'iptables -L FORWARD -v -n'

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

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

قواعد علامت‌گذاری تونل را از مسیر جدید دور نگه دارید

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

دو افزوده مسیرها را جدا می‌کند. در زنجیره mangle برای زیرشبکه فضای نام زودتر بازگردید، و یک قاعده مبتنی بر مبدأ اضافه کنید که آن زیرشبکه را در جدول اصلی قرار می‌دهد:

iptables -t mangle -I PREROUTING -s 192.168.100.0/24 -j RETURN
ip rule add from 192.168.100.0/24 lookup main priority 100

اولویت 100 روی میزبان من پیش از قواعد تونل مرتب می‌شود، بنابراین برای آن مبدأ جدول عادی تصمیم می‌گیرد. عدد را کورکورانه کپی نکنید: اولویت‌هایی که wg-quick نصب می‌کند بین نسخه‌ها و بین تنظیمات IPv4 و IPv6 فرق دارند، بنابراین اجرا کنید ip rule show و اولویتی انتخاب کنید که روی ماشین شما پیش از قواعد تونل قرار می‌گیرد.

بررسی کنید با جستجوی ویژه مبدأ به‌جای اعتماد به فهرست قواعد:

ip route get 1.1.1.1 from 192.168.100.2
ip netns exec clearnet ip route get 1.1.1.1

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

فرایندی را که اتصال را باز می‌کند راه بیندازید

راه‌اندازی فرمان یک خط است، اما فرایندی را راه بیندازید که واقعاً سوکت را می‌سازد.ip netns exec clearnet curl -s https://ifconfig.me کوچک‌ترین آزمون صادقانه است: نشانی‌ای را نشان می‌دهد که فضای نام به جهان ارائه می‌دهد، نه آن نشانی که میزبان استفاده می‌کرد.

برای یک سرویس، فضای نام را با مسیر متصل کنید تا فرایند تمام عمرش در آن بماند:

[Service]
NetworkNamespacePath=/run/netns/clearnet

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

readlink /proc/$(pgrep -f clearnet-profile | head -1)/ns/net
readlink /run/netns/clearnet

دو خروجی باید یکسان باشند. همان بررسی برای هر برنامه طولانی‌مدت کار می‌کند، و ارزش دارد یک بار برای هر برنامه انجام شود به‌جای اینکه فرض کنید راه‌انداز همان کاری را کرده که منظورتان بود.

حل نام نیاز به تصمیم خودش دارد. ساخت فضای نام به آن پیکربندی تفکیک‌کننده نمی‌دهد؛ فایل‌های مخصوص هر فضای نام از طریق /etc/netns/<name>/resolv.conf پشتیبانی می‌شوند، و بدون آن رفتار را به ارث می‌برید که به‌راحتی اشتباه خوانده می‌شود. IPv6 به همان برخورد نیاز دارد: اگر فضای نام مسیر پیش‌فرض v6 نداشته باشد در حالی که برنامه v6 را ترجیح می‌دهد، درخواست‌ها ممکن است پیش از عقب‌نشینی متوقف شوند، که مانند یک تونل خراب به نظر می‌رسد.

قاب‌بندی را بررسی کنید، نه فقط نشانی خروج

یک نشانی عمومی کارآمد مسیر را ثابت می‌کند، نه کل الزام را. بقیه را به این ترتیب طی کنید:

  • ip netns exec clearnet ip route get 1.1.1.1 مسیر پیش‌فرض veth را نشان می‌دهد، نه رابط WireGuard را.
  • شمارنده‌های FORWARD روی هر دو قاعده در طول اجرای یک درخواست افزایش می‌یابند.
  • فرایند برنامه inode فضای نامی را که انتظار دارید گزارش می‌کند.
  • پس از راه‌اندازی مجدد، فضای نام پیش از شروع سرویس وجود دارد؛ واحدی که زودتر اجرا شود شکست می‌خورد، یا بدتر، بیرون از فضای نام اجرا می‌شود.

سپس تصمیم بگیرید وقتی تونل می‌افتد چه باید بشود. فضای نام به کار خود ادامه می‌دهد، که هدف این تمرین و هم‌زمان خطر است: برنامه مستثنی متصل می‌ماند در حالی که همه چیز دیگر متوقف می‌شود. آن را به‌عنوان یک انتخاب سیاست ثبت کنید و روشن باشید که استثنا چه چیزی را پوشش نمی‌دهد — هویت حساب، وضعیت ذخیره‌شده مرورگر و ارائه‌دهنده DNS شما همه بیرون از دامنه یک فضای نام شبکه قرار دارند، و برخورد با استثنا به‌عنوان ناشناس‌بودن همان اشتباهی است که از پیکربندی بیشتر عمر می‌کند.

مقالات مرتبط