دو نام DNS، یک پورت OpenVPN: چه چیزی واقعاً انتخاب میکند
دو نام میزبان که به یک نشانی اشاره میکنند باز هم به یک شنونده میرسند. تنها فیلدی که کارخواه میفرستد میتواند یک بکاند را انتخاب کند، و OpenVPN بومی هیچکدام را نمیفرستد.
دو رکورد A، یک نشانی، یک سرویسدهنده: هر نامی که کاربر تایپ کند، بستهای که میرسد یکسان است و فرایندی که به پورت 1194 بسته شده چیزی برای تمایز آن دو ندارد. این یک پیکربندی اشتباه نیست که منتظر تعمیر باشد؛ این مرز چیزی است که یک جستوجوی نام میتواند بیان کند. هر چیزی که بین دو نمونه OpenVPN انتخاب کند باید مقداری باشد که کارخواه در اتصال میگذارد و پیشانه میتواند آن را بازخوانی کند، و کارخواه استاندارد OpenVPN هیچ چنین مقداری را آشکارا نمیگذارد. آنچه میآید این است که این شما را کجا میگذارد و کدام چیدمانها واقعاً ترافیک را تقسیم میکنند.
با آنچه حلکننده برمیگرداند شروع کنید
کارخواه vpn-a.example را میپرسد و نشانیای میگیرد؛ همان نشانی بههمراه یک پورت تمام چیزی است که با آن تماس میگیرد. نام بهصورت محلی، در هنگام جستوجو، مصرف میشود و هرگز به فیلدی روی سیم تبدیل نمیشود، بنابراین شنونده در سوی دیگر نمیتواند ببیند کدام برچسب استفاده شده است. vpn-a.example و vpn-b.example را به یک میزبان اشاره دهید و هر دو جستوجو مقصد یکسانی میدهند، و به همین دلیل سرویسدهنده هر دو اتصال را در یک نمونه جذب میکند بدون آنکه تفاوتی ثبت کند. نمایههای مبتنی بر نشانی دقیقاً مانند نمایههای مبتنی بر نام رفتار میکنند، به همان دلیل.
این همچنین خانوادهای از راهحلهای فریبنده را میبندد: نامهای مستعار اضافی، انتخاب گواهی برای هر نام روی یک سوکت، یا قاعده دیوار آتش کلیدخورده به نام پرسیدهشده. هیچیک از آنها نمیتواند بر اطلاعاتی عمل کند که پیش از خروج نخستین بسته از کارخواه دور انداخته شده است. اگر دو سرور باید جدا بمانند، تفکیک باید همراه خود اتصال سفر کند، یعنی یک نشانی، یک پورت، یا فیلد بار مفیدی که پروتکل تعریف میکند.
تنها گزینشگری که به حساب میآید درون بسته سوار میشود
HTTP این را با سرآیند Host انجام میدهد و TLS با افزونه نام سرور در ClientHello، و اینگونه یک نشانی بسیاری از سایتها را پشت یک شنونده سرو میکند. هر دو کار میکنند چون پروتکل روی سیم درخواستی برای سرویس مشخصی حمل میکند. نکته مرتبط درباره OpenVPN این است که هیچیک از آن دو فیلد در لایهای که یک جعبه میانی بازرسی میکند حضور ندارد.
در چیدمان استاندارد، دستدهی TLS که کانال کنترل را محافظت میکند پس از برقراری نشست بیرونی رخ میدهد و درون آن حمل میشود، بنابراین شنوندهای که آن نشست را پایان نداده، جریانی مات میبیند. هنوز میتواند بگوید که این OpenVPN است، چون اپکد و قاببندی در بایتهای آغازین قابل تشخیصاند، اما نام سرور، اگر وجود داشته باشد، در بخش رمزنگاریشده نشسته است. طرحی که انتظار دارد میزبان مجازی را از بسته بیرونی بخواند، فیلدی را میخواند که پروتکل هرگز آنجا نمینویسد. این از نحوه ساخت تونل میآید، نه از شکافی که تطبیق الگوی هوشمندانهتری میتوانست ببندد.
جایی که یک تقسیمکننده پروتکل کوتاه میآید
چندگانهساز از نوعی که پروژه sslh مستند میکند روی یک پورت گوش میدهد، بایتهای آغازین را بازرسی میکند و اتصال را به هر بکاندی که پروتکل شناختهشده را سخن میگوید میسپارد. این ارزش واقعی است وقتی یک پورت باید SSH و HTTPS و OpenVPN را با هم سرو کند.
sslh برای هر پروتکل یک کاوشگر جدا نگه میدارد و کاوشگر TLS آن میتواند نام سرور یا مقدار ALPN را از یک ClientHello اصیل بیرون بکشد. شناختن OpenVPN بومی طبقهبندی دیگری است نسبت به خواندن یک افزونه TLS، و این دو ترکیب نمیشوند، چون کارخواهی که هرگز ClientHello به سوکت شنود نمیفرستد کاوشگر را بدون چیزی برای خواندن رها میکند. از اینرو قاعدهای که با OpenVPN منطبق میشود پاسخ میدهد «این یک کارخواه OpenVPN است» و جلوتر نمیرود. دو بکاند OpenVPN پشت آن قاعده از هم قابل تشخیص نیستند، پیشانه هیچ مبنایی برای انتخاب ندارد، و هر نشست در همان نقطه فرود میآید. چندگانهسازی یک پورت را میان سرویسهای مختلف شریک میکند؛ درون یک سرویس میزبانی مجازی انجام نمیدهد.
چیدمانهایی که واقعاً دو سرور را جدا میکنند
ارزانترین تفکیک صادقانه یک نشانی عمومی دوم است، یکی برای هر نمونه، و نمایههای موجود از پیش آنچه لازم است را دارند چون به نشانیهای مختلف اشاره میکنند. گزینه بعدی پورتی متفاوت روی همان نشانی است که چیزی جز یک عدد در هر نمایه هزینه ندارد. TCP و UDP جدولهای پورت جداگانه نگه میدارند، بنابراین 1194/tcp و 1194/udp سوکتهایی بیارتباطاند و از هرکدام یکی میتواند روی یک میزبان همزیستی کند؛ این جداسازی انتقال است نه مسیریابی بر پایه نام، و اغلب با آن اشتباه میشود. هر دو گزینه از بازبینی دیوار آتش جان سالم به در میبرند، چون قاعده با چیزی منطبق است که بسته واقعاً در خود دارد.
اگر مرزی که نیاز دارید میان گروههای کاربران میگذرد نه میان دو پیادهسازی، یک نمونه با پیکربندیهای متفاوت کارخواه، مدیریت گواهی خودش و سیاست دسترسی صریح میتواند آن را بپوشاند. آنچه این میخرد سیاست درون یک سرور است، نه جداسازی میان سرورها، و این دو نیازمندی متفاوتی هستند. جداسازیای که باید زیر نفوذ دوام بیاورد هنوز به نشانی یا لبه دیوار آتش نیاز دارد.
یک پایاندهنده TLS که پیش از OpenVPN گذاشته شود میتواند نام سرور واقعی را به پیشانهای توانمند آشکار کند، اما فقط وقتی سوی کارخواه هم برای آن لایه اضافی پیکربندی شده باشد. نمایههای موجود این رفتار را با اشاره به همان نشانی به دست نمیآورند.
پیش از ساختن گزینشگر را اثبات کنید
فیلدی را که یک بکاند را شناسایی خواهد کرد نام ببرید، سپس تأیید کنید که کارخواه واقعاً آن را میفرستد؛ اگر پاسخ یک نشانی است طرح میایستد، و اگر نام سروری درون دستدهی باشد که هرگز به شنونده نمیرسد، هیچ مقدار کار DNS نجاتش نخواهد داد. سه فرمان سوی شنود را سریع روشن میکند.
ss -lntup | grep -E ':443|:1194'
openssl s_client -connect vpn-a.example:443 -servername vpn-a.example </dev/null | head -n 20
journalctl -u openvpn-server@server-a -n 20 --no-pager
خط openssl تنها جایی گواهی میدهد که چیزی روی آن نشانی TLS را پایان میدهد؛ در برابر شنونده بومی OpenVPN گیر میکند یا شکست میخورد، و این خودش پاسخ این است که لایه بیرونی چه آشکار میکند. خط journal که روی هر بکاند خوانده شود نشان میدهد کدام نمونه نشست را پذیرفته است. گزارشهای پیشانه ثبت میکنند چه طبقهبندی شد و هرگز چه قصد شده بود، بنابراین بکاند تنها مرجع درباره این میماند که کاربر کجا فرود آمده است.
با دو نمایه که برای رسیدن به سرورهای متفاوت ساخته شدهاند تمام کنید، آنها را یکییکی وصل کنید و گزارش بکاند هرکدام را یادداشت کنید. اگر هر دو نشست در یک journal پیدا شوند، گزینشگر غایب است نه بدپیکربندی، و اصلاح یک نشانی یا پورتی است که کارخواه میتواند هدف بگیرد. ویرایش قاعده مسیریابی کمکی نمیکند، چون به قاعده هرگز چیزی برای مسیریابی داده نشده است. وقتی تفکیک واقعی شد، آن را کنار نمایهها بنویسید تا نفر بعد نام مستعار دومی اضافه نکند و انتظار داشته باشد کار را انجام دهد.