نامهای کلاینت OpenVPN در dnsmasq: اسکریپت یا ورودیهای ثابت؟
نشانی کلاینتها تغییر میکند، نام سرویسها نه. نام کلاینتها را از نشست VPN بسازید، نام سرویسها را در یک فایل drop-in ثابت کنید و سپس کلاینتها را وادار کنید از آن استفاده کنند.
دو مشکل نام تقریباً روی هر دروازه کوچک OpenVPN پیش میآید. نمیتوانید به لپتاپ متصل با نامی که در گواهیاش هست دسترسی پیدا کنید، و سرویسهای پشت تونل اصلاً نامی ندارند. شبیه یک مشکل به نظر میرسند و به درمانهای متضاد نیاز دارند، چون یک نشانی با هر نشست جابهجا میشود و دیگری نه. پیش از ویرایش هر چیزی تصمیم بگیرید چه نوع نامی اضافه میکنید.
برای هر نام تصمیم بگیرید، نه برای هر دروازه
آزمون ساده است: آیا این نشانی وقتی کلاینت دوباره وصل میشود تغییر میکند؟ اگر بله، نام باید از نشست VPN ساخته شود. اگر نه، به یک ورودی ثابت تعلق دارد که میتوانید بخوانید و بازبینی کنید.
| Name kind | Source of truth | Where it lives |
|---|---|---|
| Connected client | The address OpenVPN just assigned | Generated hosts file, rewritten per session |
| Service behind the tunnel | A fixed address you chose | Static address= drop-in |
| Anything with a certificate name | The certificate, not the pool | Either, but the name must match the certificate |
قاطی کردن این دو همان شکست معمول است. سرویسی که در فایل ساختهشده ثابت شده، نخستین بار که اسکریپت آن را بازنویسی میکند ناپدید میشود، و کلاینتی که در ورودی ثابت نوشته شده به کسی اشاره میکند که آن نشانی را آخرین بار داشته است. هر دو خطا نامرئی میمانند تا وقتی نامی به دستگاه اشتباه تبدیل شود. تا آن زمان کسی که آن را اشکالزدایی میکند گمان میکند DNS خراب است نه فایل.
مسیر پویا: learn-address و استخر
OpenVPN تخصیص را میداند، پس بگذارید به شما بگوید. این گزینههای سرور تخصیص را پایدار و قابل اسکریپتنویسی میکنند:
client-config-dir /etc/openvpn/ccd
ifconfig-pool-persist /etc/openvpn/ip-pool 60
script-security 2
learn-address /etc/openvpn/learn-address.sh
learn-address هر بار که نشانیای افزوده، بهروز یا حذف میشود اسکریپت شما را اجرا میکند و عملیات، نشانی و نام مشترک را میفرستد. یک اسکریپت کمینه برای هر کلاینت یک خط اضافه میکند و هنگام حذف آن را برمیدارد:
#!/bin/sh
HOSTS=/etc/openvpn/hosts.lan
case "$1" in
add|update) echo "$2 $3" >> "$HOSTS" ;;
delete) sed -i "/^$2 /d" "$HOSTS" ;;
esac
kill -HUP $(cat /var/run/dnsmasq.pid)
روی دستگاه tun آرگومان دوم نشانی تونل کلاینت است، پس خط مستقیماً قابل استفاده است. روی دستگاه tap، OpenVPN بهجای آن نشانی MAC کلاینت را میفرستد، چون یک بخش tap میتواند پروتکلهایی جز IPv4 را هم حمل کند، و آنگاه باید پیش از نوشتن هر چیزی نشانی را با نام مشترک در فایل استخر پیدا کنید.
روشن باشید که فایل ساختهشده چیست: تصویری از اینکه هماکنون چه کسی متصل است. نامها هنگام قطع اتصال ناپدید میشوند، که دقیقاً همان چیزی است که برای لپتاپهایی که بین شبکهها جابهجا میشوند میخواهید و دقیقاً همان چیزی که برای سروری که تمام شب روشن است نمیخواهید.
مسیر ثابت: address= و گسترش دامنه
dnsmasq را بهجای فایل hosts سیستم به فایل ساختهشده اشاره دهید و به آن دامنهای بدهید تا نامهای کوتاه به نامهای کاملاً واجد شرایط گسترش یابند:
domain=corp.example
no-hosts
addn-hosts=/etc/openvpn/hosts.lan
listen-address=127.0.0.1,10.8.0.1
bind-interfaces
وقتی domain تنظیم شده باشد، خطی مانند 10.8.0.6 alice هم برای alice و هم برای alice.corp.example پاسخ میدهد. listen-address را محدود به دروازه تونل و loopback نگه دارید، چون resolver که بهاشتباه روی رابط LAN منتشر شود سرویسی است که قصد ارائهاش را نداشتید.
سرویسهایی که هرگز از استخر نمیآیند ورودیهای خودشان را دارند. آنها را در یک فایل drop-in جداگانه زیر پوشه پیکربندی توزیع بگذارید تا ارتقای بسته نتواند بازنویسیشان کند:
address=/files.corp.example/10.8.0.20
address=/db.corp.example/10.9.0.5
resolver را تحویل بدهید وگرنه هیچ اتفاقی نمیافتد
resolverی که هیچکس از آن نمیپرسد چیزی را تغییر نمیدهد. سرور باید آن را اعلام کند:
push "dhcp-option DNS 10.8.0.1"
push "dhcp-option DOMAIN corp.example"
کلاینتهای Windows هر دو گزینه را خودشان اعمال میکنند. بیشتر کلاینتهای Linux این کار را نمیکنند: به یک یکپارچگی پشتیبانیشده resolver نیاز دارند، مانند قلاب update-resolv-conf توزیع یا مدیریت DNS در NetworkManager، یا دامنه جستوجو و سرور نام دستی. resolver واقعی کلاینت را بررسی کنید بهجای اینکه فرض کنید push رعایت شده، چون push نادیدهگرفتهشده دقیقاً مانند سروری است که پاسخ نمیدهد.
در سه لایه بررسی کنید
نخست مستقیم از سرور بپرسید، سپس از یک کلاینت، سپس از برنامه:
dig +short @10.8.0.1 alice.corp.example
getent hosts files.corp.example
اگر پرسوجوهای مستقیم پاسخ میدهند و برنامه نه، خطا در تحویل به کلاینت است نه در ناحیه. اگر نام حل میشود و اتصال همچنان شکست میخورد، نام درست است و چیز بعدی که باید بررسی شود مسیر یا دیوار آتش است.
دو دسته را کنار پیکربندی بنویسید: کدام نامها ساخته میشوند، کدام ثابتاند و هر یک باید با کدام گواهی مطابقت داشته باشد. نفر بعدی که سروری اضافه میکند هر الگویی را که اول بیابد کپی میکند.