دو سایت، یک زیرشبکه، یک هاب WireGuard: کارش را راه بیندازید
هر دو LAN روی 10.10.7.0/24 هستند، پس هاب نمیتواند سایت را بر اساس مقصد انتخاب کند. به هر سرویس یک نام مستعار بدهید و در دروازهاش ترجمه کنید.
هر دو سایت از یک محدوده LAN استفاده میکنند و همپوشانی چیزی نیست که واقعاً طراحی را خراب میکند. هاب باید سایت را تنها با آدرس مقصد انتخاب کند و دو مقصد یکسان چیزی برای انتخاب به آن نمیدهد. شمارهگذاری مجدد یک دفتر کارآمد برای راضی کردن یک تونل معمولاً معامله بدتری است از دادن یک آدرس متمایز به هر سرویس منتشرشده که تونل بتواند حمل کند. طراحی زیر یک سرویس HTTPS به ازای هر سایت منتشر میکند و نه چیز دیگری.
چرا همپوشانی مشکل واقعی نیست
WireGuard بر اساس مقصد ارسال میکند: AllowedIPs یک peer تعیین میکند کدام peer بسته را دریافت میکند. دو peer نمیتوانند هر دو 10.10.7.0/24 را اعلام کنند بدون اینکه یکی از آنها هر جستجو را ببرد. این ویژگی جدول peer است نه تونل، و به همین دلیل راهحل اینجا یک طرح آدرس است و نه ترفند مسیریابی.
طرح این است که اصلاً LAN را اعلام نکنیم. به جای آن برای هر سرویس یک نام مستعار اعلام کنید، یک آدرس به ازای هر سایت، و بگذارید دروازه هر سایت آن نام مستعار را به برنامه واقعی خود ترجمه کند.
کاربر دو آدرس یکتا را مسیریابی میکند، هرگز پیشوند مبهم را نمیبیند و چیزی در هیچ یک از دو دفتر تغییر نمیکند. این مرز را هم صادقانه بیان میکند: شما یک سرویس HTTPS از هر سایت منتشر میکنید، نه ادغام دو شبکه. قواعدی که میآیند کوچک میمانند چون گزاره باریک است. گزاره گستردهتر به قواعد گستردهتری نیاز داشت و اینگونه است که این طراحیها پیچیده میشوند.
به هر سایت یک نام مستعار بدهید که کاربر بتواند مسیریابی کند
آدرسها را از محدودهای انتخاب کنید که با هیچ چیز روی دستگاه کاربر، هاب یا هیچ یک از دو LAN تعارض نداشته باشد. اینجا هاب 10.66.0.1 است، کاربر 10.66.0.10، دروازهها 10.66.0.21 و 10.66.0.22، و دو نام مستعار 10.77.1.20 و 10.77.2.20 هستند. هاب هر نام مستعار را از طریق peer که مالک آن است منتشر میکند، بنابراین بسته خروجی خطاب به یک نام مستعار تنها میتواند از سایت متناظر خارج شود:
[Interface]
Address = 10.66.0.1/32
ListenPort = 51820
PrivateKey = HUB_KEY
[Peer]
PublicKey = USER_PUBLIC_KEY
AllowedIPs = 10.66.0.10/32
[Peer]
PublicKey = SITE_A_PUBLIC_KEY
AllowedIPs = 10.66.0.21/32, 10.77.1.20/32
[Peer]
PublicKey = SITE_B_PUBLIC_KEY
AllowedIPs = 10.66.0.22/32, 10.77.2.20/32
سمت کاربر فقط به دو نام مستعار نیاز دارد، که پیکربندی کلاینت را از هر دو پیشوند LAN آزاد نگه میدارد. هیچ چیز در آن پیکربندی به هیچ یک از LANهای واقعی اشاره نمیکند:
[Interface]
Address = 10.66.0.10/32
PrivateKey = USER_KEY
[Peer]
PublicKey = HUB_PUBLIC_KEY
Endpoint = hub.example.net:51820
AllowedIPs = 10.77.1.20/32, 10.77.2.20/32
PersistentKeepalive = 25
هر دروازه هاب و مبدأ کاربر را اعلام میکند، نه چیز دیگری، بنابراین یک سایت هرگز LAN سایت دیگر را نمیآموزد. Keepalive یک نگاشت NAT روی لینک بالاسری سایت حفظ میکند؛ این ترافیک را مجاز نمیکند و دیوار آتش همچنان تصمیم میگیرد چه چیزی پذیرفته شود. کپی پیکربندی یک دروازه به دیگری اشکالی ندارد به شرطی که کلید خصوصی، آدرس رابط و نام مستعار همه تغییر کنند.
هاب باید بین دو peer خود چه چیزی را مجاز کند
هاب بستهها را بین دو peer خود ارسال میکند، که تصمیمی در زنجیره forward است نه تصمیم ورودی. ارسال IPv4 را با مکانیزم معمول پلتفرم فعال کنید، سپس دقیقاً همان جفتهایی را که طراحی نیاز دارد مجاز کنید.
قاعده زیر به کاربر یک نام مستعار و یک پورت اجازه میدهد و ترافیک بازگشتی را از طریق ردیابی اتصال مجاز میکند. هر چیز دیگری را در مسیر forward دور میریزد و این همان نکته است:
nft add table inet hub_transit
nft add chain inet hub_transit forward '{ type filter hook forward priority 0 ; policy drop ; }'
nft add rule inet hub_transit forward ct state established,related accept
nft add rule inet hub_transit forward iifname wg0 oifname wg0 tcp dport 443 ip saddr 10.66.0.10 ip daddr 10.77.1.20 accept
دو جزئیات ارزش گفتن دارند چون شکستهای خاموش ایجاد میکنند. accept در یک زنجیره پایه، drop در زنجیره دیگر را باطل نمیکند، پس این را با سیاست موجود ادغام کنید نه اینکه کنار آن بارگذاری کنید. و آدرس مبدأ دستگاه را شناسایی میکند نه شخص را؛ احراز هویت برنامه را از پذیرش شبکه جدا نگه دارید.
جایی که نام مستعار به آدرس واقعی تبدیل میشود
سایت A درخواستی برای 10.77.1.20 دریافت میکند، مقصد را به برنامه واقعی بازنویسی میکند و مبدأ را به آدرس LAN خودش بازنویسی میکند تا پاسخ بدون مسیر به تونل بازگردد. انجام هر دو ترجمه در یک جا بقیه شبکه را از نام مستعار بیخبر نگه میدارد. قواعد زیر تمام مکانیزم هستند:
nft add table ip site_a_nat
nft add chain ip site_a_nat pre '{ type nat hook prerouting priority -100 ; policy accept ; }'
nft add chain ip site_a_nat post '{ type nat hook postrouting priority 100 ; policy accept ; }'
nft add rule ip site_a_nat pre iifname wg0 tcp dport 443 ip saddr 10.66.0.10 ip daddr 10.77.1.20 dnat to 10.10.7.20:443
nft add rule ip site_a_nat post iifname wg0 oifname lan0 tcp dport 443 ip saddr 10.66.0.10 ip daddr 10.10.7.20 snat to 10.10.7.2
سیاست forward سایت A سپس باید جریان ترجمهشده از رابط تونل به رابط LAN را بهعلاوه جهت بازگشت مجاز کند. قلاب forward مقصد را پس از ترجمه مقصد و پیش از بازنویسی مبدأ میبیند، به همین دلیل قاعده آدرس برنامه واقعی را نام میبرد. هر وقت قاعدهای به نظر میرسد با هیچ چیز مطابقت ندارد، آن دو قلاب را به همین ترتیب بخوانید. قاعده forward نوشتهشده علیه نام مستعار هرگز نمیتواند مطابقت کند، چون نام مستعار در آن قلاب دیگر وجود ندارد.
سایت B این را با نام مستعار و کلید خود تکرار میکند. نباید از کلید خصوصی سایت A دوباره استفاده کند، چون دو peer که یک هویت را به اشتراک میگذارند خطای پیکربندی است که دیدنش سخت و ساختنش با کپی یک فایل آسان است. هر دو سند دروازه را به جز مقادیری که باید متفاوت باشند یکسان نگه دارید تا تفاوت در بازبینی برجسته شود. فایل کپیشده منشأ معمول آن خطاست.
بازنویسی مبدأ هزینه دارد. برنامه دروازه را به عنوان کلاینت خود میبیند، پس گزارشهایش دیگر نشان نمیدهند کدام کاربر متصل شده است. ردپای حسابرسی دروازه را نگه دارید و ورود برنامه را برای جبران هویت شبکهای که ترجمه حذف کرده ضعیف نکنید.
چگونه ثابت کنید هر دو نام منتشرشده پاسخ میدهند
به هر نام مستعار یک نام DNS بدهید و برنامه و گواهی را برای آن نام پیکربندی کنید، چون ترجمه تغییرمسیرها یا URLهای مطلق جاسازیشده را بازنویسی نمیکند. یک نام به ازای هر سایت استفاده کنید تا عدم تطابق گواهی هرگز با خطای مسیریابی اشتباه گرفته نشود.
از کلاینت واقعی آزمایش کنید، تأیید کنید کدام سایت پاسخ داد، و یک پورت غیرمجاز را هم آزمایش کنید. پس از هر تغییر NAT از اتصالهای جدید استفاده کنید، چون وضعیت برقرارشده نگاشت قدیمی را حفظ میکند:
wg show wg0 allowed-ips
sudo nft list ruleset
curl -sS -o /dev/null -w "%{http_code}\n" https://site-a.example.net/
نام مستعار خالی یا غیرمنتظره در فرمان اول یعنی انتخاب peer پیش از آنکه هر قاعده دیوار آتشی مهم باشد اشتباه است. اگر نام مستعار درست است و نام هنوز کار نمیکند، مشکل به DNS و گواهیها منتقل شده است. وقتی هر دو نام پاسخ میدهند و پورت سوم بسته میماند، طراحی همان کاری را میکند که ادعا میکند: دو سرویس با انتشار باریک، نه دو LAN ادغامشده.