دسترسی به سرویس روی کلاینت VPN: تونل معکوس یا DNAT
دسترسی به سرویس روی کلاینت OpenVPN بدون انتقال پورت: تونل معکوس SSH را با DNAT سمت سرور و سه شرطی که انتخاب را تعیین میکنند مقایسه کنید.
حتی لپتاپی پشت NAT اپراتور هم میتواند به همکاری خدمت کند، به شرطی که سرور VPN نقش نقطه دیدار را بازی کند. دو سازوکار به آنجا میرسند: کلاینت به بیرون وصل میشود و از سرور میخواهد یک پورت شنود نگه دارد، یا سرور پورتی را منتشر میکند و آن را به درون تونل ترجمه میکند. هر دو همان مشکل دسترسپذیری را حل میکنند و در برابر خرابی، نظارت و ثبت متفاوت رفتار میکنند. سه شرط تعیین میکند کدامیک به تنظیمات شما تعلق دارد.
دو شکل، یک نقطه دیدار
در شکل اول کلاینت یک نشست SSH به بیرون باز میکند و از سرور میخواهد روی پورت انتخابی گوش دهد و هر اتصال را از همان نشست بازمیگرداند. روی سرور چیزی منتقل نمیشود و هیچ ترجمه بستهای رخ نمیدهد، پس تنها الزامها یک حساب SSH، یک انتقال مجاز و یک قاعده دیوار آتش برای پورت است. سرویس به loopback روی کلاینت گره میخورد که معمولاً همان چیزی است که میخواهید.
ssh -N -R 8081:127.0.0.1:8080 -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 [email protected]
در شکل دوم سرور مالک پورت عمومی است و هر اتصال را به سمت نشانی تونل کلاینت بازنویسی میکند. این کار انتقال IP فعال، ترجمه مقصد در مسیر ورود و ترجمه مبدأ در مسیر خروج میخواهد و وقتی هیچ نشست SSH وجود ندارد هم به کار ادامه میدهد. پورت به سرور تعلق دارد نه به یک نشست، و همین ویژگی بیشتر موارد واقعی را تعیین میکند.
هیچیک از دو شکل به خودی خود امنتر نیست. هر دو یک پورت سرویس را برای هر کسی که به نشانی عمومی سرور برسد باز میکنند و هر دو همچنان به احراز هویت خود سرویس وابستهاند.
شرط اول: آیا پورت باید بیش از نشست زنده بماند
انتقال معکوس دقیقاً به اندازه نشست SSH که آن را ساخته زنده میماند. وقتی پیوند قطع شود شنونده ناپدید میشود و همکار به جای مسیر کند، اتصال ردشده میبیند. نظارت بر فرمان با یک واحد systemd و سیاست راهاندازی مجدد این را حل میکند و ExitOnForwardFailure=yes گرهخوردن ناموفق را فوری نمایان میکند به جای اینکه نشستی بدون انتقال رها شود.
پورت ترجمهشده در صورت ماندگاری قاعدهها از راهاندازی مجدد جان سالم به در میبرد، اما به حفظ همان نشانی تونل توسط کلاینت بستگی دارد. یک استخر پویا که پس از اتصال مجدد نشانی دیگری به لپتاپ میدهد، قاعده را بیصدا به هیچجا میفرستد. نخست نشانی تونل را رزرو کنید، سپس قاعده را بنویسید و هر دو را یک تغییر واحد بدانید.
اگر سرویس باید ساعت سه بامداد بدون هیچ ناظری پاسخ دهد، شکل با پورت منتشرشده توسط سرور قطعات متحرک کمتری دارد، چون تنها فرایندی که باید برپا بماند خود تونل است.
شرط دوم: دیوار آتش و گزارشها از آنِ کیست
شکل معکوس همه سیاست را در دو جا نگه میدارد. sshd از طریق AllowTcpForwarding تعیین میکند که آیا انتقالهای راه دور بهکلی مجازند و GatewayPorts تعیین میکند که شنونده به loopback گره بخورد یا به همه نشانیها. با مقدار پیشفرض no همکاری بیرون از سرور با اینکه انتقال موفق بوده نمیتواند به پورت برسد و این شبیه تونل خراب به نظر میرسد در حالی که واقعاً نشانی گرهخوردن است.
sudo ss -ltn '( sport = :8081 )'
sudo grep -E '^(GatewayPorts|AllowTcpForwarding)' /etc/ssh/sshd_config
شکل ترجمهشده انتقال فعال و دو قاعده میخواهد و قاعده دوم جایی است که بیشتر دستورالعملها اشتباه میکنند. محدودکردن ترجمه مبدأ به وضعیت conntrack DNAT یعنی فقط اتصالهایی که قاعده مقصد ساخته بازنویسی میشوند، نه هر بستهای که سرور به تونل میفرستد.
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8081 -j DNAT --to-destination 10.88.0.6:8080
sudo iptables -t nat -A POSTROUTING -o tun0 -m conntrack --ctstate DNAT -j SNAT --to-source 10.88.0.1
این بازنویسی انتساب را هم از بین میبرد. پس از آن کلاینت هر تماسگیرنده را نشانی تونل سرور میبیند که هر محدودیت نرخ بر پایه نشانی را در یک سطل فرومیآورد و پنهان میکند چه کسی چه فرستاد. اگر انتساب مهم است، اتصال را روی سرور پایان دهید یا تصمیم اجازه را همانجا نگه دارید و هویتی را در سرآیندی که سرویس به آن اعتماد دارد منتقل کنید. انتخاب میان این دو اصلاح بستگی دارد به اینکه آیا سرویس اصلاً سرآیند پروکسی میخواند یا نه.
شرط سوم: یک پورت یا چند پورت، و نام از آنِ کیست
یک سرویس روی یک پورت همان موردی است که انتقال معکوس در تلاش برنده میشود. به یک فرمان، یک حساب و یک قاعده دیوار آتش نیاز دارید و پاکسازی یعنی کشتن نشست. چند سرویس روی همان نشانی عمومی شما را به سمت شکل منتشرشده توسط سرور میراند، چون هر انتقال معکوس پورت سرور خودش را میخواهد و مجموعه با هر سرویس بزرگتر میشود.
نامها کار را پیچیدهتر میکنند. انتقال معکوس میتواند پشت یک پروکسی TCP باشد که بر پایه SNI مسیریابی میکند، در حالی که پورت ترجمهشده معمولاً یک پورت برای هر سرویس است. اگر سرویس خودش TLS را پایان میدهد و به نام میزبان اصلی نیاز دارد، رویکرد پروکسی آن را حفظ میکند و رویکرد DNAT تنها وقتی حفظش میکند که سرویس آن نام را روی آن پورت بپذیرد.
بنویسید کدامیک از سه شرط شکل را تعیین کرد. در غیر این صورت نفر بعدی که سرویس دومی اضافه میکند همان مقایسه را با زمینه کمتر دوباره باز میکند.
تصمیم بگیرید، سپس از بیرون آزمایش کنید
مسیر را از شبکهای آزمایش کنید که هیچ مسیری به لپتاپ ندارد و هنگام اجرای درخواست شمارندههای سرور را ببینید. آزمایش از سرور به نشانی عمومی خودش اینجا چیزی را ثابت نمیکند، چون بسته به صورت محلی ساخته میشود و هرگز به قلاب ترجمه ورودی نمیرسد، پس ممکن است آزمایش موفق شود در حالی که مسیر واقعی خراب است.
sudo iptables -t nat -L PREROUTING -n -v
sudo tcpdump -ni any 'tcp port 8081' -c 20
شمارندههایی که ثابت میمانند یعنی بسته هرگز به قاعده نرسیده است که به ارائهدهنده یا دیوار آتش میزبان اشاره دارد. شمارندههایی که هنگام رد کردن سرویس حرکت میکنند به دیوار آتش خود کلاینت یا نشانیای که سرویس روی آن گوش میدهد اشاره دارند. تونلی که بسته را میبرد اما چیزی برنمیگرداند یک مشکل مسیر یا مسیر بازگشت است، و هیچیک از این سه نتیجه نباید با ویرایش مبدل کلاینت عیبیابی شود. پیش از تغییر هر چیزی بنویسید کدام شمارنده حرکت کرد، چون آزمایش بعدی به همان خط مبنا نیاز دارد.
وقتی شکل کار کرد، پورت، مالک و روش نظارت را کنار پیکربندی تونل ثبت کنید. اصلاح دسترسپذیری که فقط در تاریخچه پوسته کسی وجود دارد، یک راهاندازی مجدد تا حادثهای تکراری فاصله دارد.