لاگی که شما را بهتر از تاریخچهٔ مرورگرتان توصیف میکند
پیش از آنکه ماشینِ شما بتواند حتی یک بایتِ رمزنگاریشده به یک وبسایت بفرستد، باید از کسی بپرسد آن وبسایت کجا زندگی میکند. آن پرسش بهصورتِ باز و خوانا سفر میکند، بهسمتِ ریزالوری که تقریباً مطمئناً خودتان انتخابش نکردهاید، و جوابِ اینکه چه کسی آن را نگه میدارد تعیین میکند چهمقدار از زندگیِ شما ثبت میشود. تاریخچهٔ مرورگر فهرستی از صفحاتی است که خودتان انتخاب کردهاید نگهش دارید. لاگِ یک ریزالور همهچیز است: هر سایت، هر اپی که برای بهروزرسانی چک میکند، هر سرویسِ ابری که گوشیِ شما وقتی خوابید با آن حرف میزند، هر دامنه در هر ایمیلی که باز کردهاید، بهترتیب، با تایماستمپ، فرق نمیکند کسی به صفحه نگاه میکرده یا نه.
یک هفته از آن را بخوانید و میتوانید یک انسان را بازسازی کنید. بانکی که استفاده میکند، هواپیمایی که همین تازه رزرو کرده، داروخانه، اپِ دوستیابی، سیستمِ پیگیریِ متقاضیانِ کارگزارِ استخدام، ساعتی که بیدار میشود و ساعتی که کارش را تمام میکند. هیچکدام از اینها نیاز به شکستنِ هیچ رمزنگاریای ندارد. خودِ نامها بهتنهایی این را حمل میکنند، و نامها همان تنها بخشِ تراکنشاند که هنوز، در بیشترِ چینشها، عمداً به یک شخصِ ثالث سپرده میشود.
امروز آن شخصِ ثالث هر کسی است که DHCP شما بهسمتش اشاره کرده — ISPتان، کارفرمایتان، کافه. آدمهایی که متوجهِ این میشوند معمولاً به یک ریزالورِ عمومی کوچ میکنند، که از نظرِ صداقت واقعاً بهتر است و از نظرِ حریمِ خصوصی فقط یک حرکتِ جانبی: ناظر را حذف نکردهاید، فقط شرکتی که ناظر است را عوض کردهاید، و یک telco تحتِ نظارت را با یک CDN نزدیکبهتبلیغات یا یک سازمانِ غیرانتفاعی که سیاستش میتواند با بودجهاش عوض شود معامله کردهاید. خوبهایش سیاستهای نگهداریِ صادقانه منتشر میکنند و بعضیهایشان واقعاً به آنها عمل میکنند. اما یک سیاست، یک وعده دربارهٔ رفتار است، و یک فایلِ کانفیگ، بیانیهای دربارهٔ قابلیت است. نمیتوانید یک وعده را audit کنید. میتوانید بیست خطی را که خودتان نوشتهاید audit کنید، روی باکسی که خودتان اجاره کردهاید، در کشوری که خودتان انتخابش کردهاید.
SP·02فوروارد کردن لاگ را جابهجا میکند. بازگشت آن را تکهتکه میکند.
تقریباً هر نوشتهای که میگوید "سرورِ DNS خودتان را اجرا کنید" در نهایت یک فورواردر میسازد: یک کشِ کوچک روی شبکهٔ شما که هر چیزی را که نمیداند به 1.1.1.1 یا 9.9.9.9 پاس میدهد. این کارِ واقعاً مفیدی است — سریع است، پنج خط است، و جلوی این را میگیرد که شبکهٔ محلیِ شما تماشایتان کند. اما لاگِ تجمیعشده را هم دقیقاً همانجا که بود میگذارد. هر نامی که جستجو میکنید همچنان به یک شرکت میرسد، اینبار بهشکلی راحت با تکِ آدرسِ IP ریزالورتان از قبل برچسبگذاریشده، که جریانِ داده را راحتتر برای انتساب میکند نه سختتر.
یک ریزالورِ بازگشتی خودش این کار را انجام میدهد بهجای آنکه آن را واگذار کند. وقتی از آن news.example.io خواسته میشود، از یک سرورِ ریشه میپرسد چه کسی .io را اداره میکند، بعد از سرورهای .io میپرسد چه کسی example.io را اداره میکند، بعد مستقیماً از همان اپراتور میپرسد. سه گفتوگو با سه طرفِ نامرتبط، که هیچکدامشان کارش تجمیعِ داده نیست، و — این همان بخشی است که اهمیت دارد — هیچکدامشان هرگز کلِ جریانِ کوئریِ شما را نمیبیند. اپراتورهای ریشه فقط چکهای از درخواستهای TLD میبینند. Verisign فقط میبیند کسی روی آدرسِ شما چیزی زیرِ .com را لمس کرده. سروری که مسئولِ یک دامنه است همان ترافیکی را میبیند که همیشه قرار بود ببیند، چون شما دیگر میخواهید مستقیماً به آن وصل شوید.
QNAME minimisation این را بهطورِ قابلتوجهی تیزتر میکند، و Unboundِ مدرن این کار را بهطورِ پیشفرض انجام میدهد. بهجای فرستادنِ کلِ نام به هر سرورِ داخلِ زنجیره — که همان کاری است که ریزالورها سی سال انجام میدادند — به هر سرور فقط همان لیبلی را میدهد که برای پاسخدادن لازم دارد: io. به ریشه، example.io. به سرورهای .io، و فقط در انتها news.example.io.ِ کامل را به همان اپراتوری که حقش است. سلسلهمراتب دیگر پخشِ نیتهای شما نیست و همان چیزی میشود که از اول ترسیم شده بود: یک واگذاری.
این معامله واقعی است و ارزش دارد صریح گفته شود. یک جستجوی بازگشتیِ سرد چند رفتوبرگشت لازم دارد، جایی که یک فورواردر فقط یکی لازم دارد، پس اولین بازدید از یک دامنهٔ ناآشنا بهطورِ قابلاندازهگیری کندتر است. مسئولیتِ یک کش را به ارث میبرید که قبلاً مشکلِ یک نفرِ دیگر بود. و دیگر از یک کشِ مشترک که میلیونها نفرِ دیگر گرمش کردهاند بهره نمیبرید. در ازایش، رکوردِ کامل، مرتب و دارای تایماستمپ از هر چیزی که نگاهش کردهاید، دیگر جایی خارج از دیسکِ خودتان وجود ندارد.
SP·03این کار چه چیزی را پنهان میکند، و صریحاً چه چیزی را پنهان نمیکند
دامنهٔ صادقانهٔ این کار کوچکتر از چیزی است که بازاریابیِ دوروبَرِ DNSِ خصوصی نشان میدهد، و دانستنِ مرزهایش همان چیزی است که شما را از گرفتنِ یک تصمیمِ بد بر اساسِ یک حسِ خوب دور نگه میدارد.
این کار فقط یک چیز را حذف میکند: لاگِ تجمیعشدهٔ نامها که در دستِ یک ناظرِ واحد است. این چیزِ کوچکی نیست، چون همین تجمیع است که ارزشِ تجاری دارد و بهصورتِ عمده درخواست میشود. همهچیز نیست.
این کار اتصال را پنهان نمیکند. بعد از آنکه جستجو resolve شد، دستگاهِ شما همچنان یک نشست به همان آدرس باز میکند، و هر کسی که آپلینکِ شما را تماشا میکند آدرسِ IP مقصد را میبیند. برای سایتی روی زیرساختِ اختصاصی، همان IP همان هویت است. hostname روی سیم را هم پنهان نمیکند: مگر آنکه هر دو سر از Encrypted Client Hello پشتیبانی کنند، دستدهیِ TLS همچنان نامِ سرور را بهصورتِ متنِ ساده حمل میکند، که همان اطلاعاتی است که ریزالورِ شما هم میداشت.
این کار کوئریها را از دیدِ ارائهدهندهٔ هاستینگِ شما پنهان نمیکند. این همان چیزی است که آدمها معمولاً اشتباه میگیرند، پس ارزش دارد بدونِ تعارف گفته شود: ترافیکِ بالادستیِ ریزالورِ شما — همان پرسشهایی که از ریشه، TLD و سرورهای authoritative میپرسد — از VPS روی پورتِ 53 با UDP، بدونِ رمزنگاری، خارج میشود، و شبکهای که سرورِ شما رویش نشسته میتواند همهٔ آن را بخواند. هیچ DoTای تا ریشه وجود ندارد. شما ناظر را حذف نکردهاید، بیشتر جابهجایش کردهاید: از یک ISPِ خانگی که داده میفروشد و در کشورِ خودتان به احضاریهها پاسخ میدهد، به یک شبکهٔ هاستینگ در حوزهٔ قضاییای که عمداً انتخابش کردهاید، که بهلطفِ QNAME minimisation فقط یک جریانِ تکهتکهشده میبیند. این یک پیشرفتِ واقعی است، و بحثی است دربارهٔ قانونِ کدام کشور روی سیم اعمال میشود نه چیزی که یک فایلِ کانفیگ بتواند حلش کند.
و این کار به شما یک جمعیت نمیدهد. ریزالوری که فقط یک خانوار از آن استفاده میکند، هر کوئری داخلش را بدونِ هیچ ابهامی به همان خانوار نسبت میدهد. در برابرِ یک دشمنِ passive و سراسری، یک ریزالورِ مشترکِ پرترافیک واقعاً پناهگاهِ بهتری است. در برابرِ ISPتان، کارفرمایتان، دلالهای دادهای که تلهمتریِ ریزالور میخرند، و درخواستهای عمده و روتینی که واقعاً برای آدمهای معمولی اتفاق میافتد، ریزالورِ خودتان بهتر است — به شرطی که آخرین گامِ از دستگاههای شما داخلِ یک تونل باشد. این کار را همراه با تونلِ WireGuardِ خودتان اجرا کنید، نه بهجای آن. یک ریزالورِ خصوصی بهتنهایی بیشتر متادیتای شما را جابهجا میکند. پشتِ یک تونل، همان تنها کانالی را میبندد که تونل باز میگذارد.
SP·04اشتباهی که ریزالورِ شما را به سلاحِ یک نفرِ دیگر تبدیل میکند
دقیقاً یک راه برای اینکه این کار را خیلی بد خراب کنید وجود دارد، بهراحتی هم میشود تصادفاً انجامش داد، و عواقبش پیش از آنکه به شما برسد به غریبهها میرسد.
ریزالوری که به هر کسی پاسخ میدهد یک ریزالورِ باز است، و یک ریزالورِ باز یک تقویتکننده است. DNS روی UDP کار میکند، آدرسهای مبدأِ UDP بهسادگی جعل میشوند، و یک کوئریِ کوچک میتواند پاسخی چندینبرابرِ اندازهٔ خودش تولید کند. یک مهاجم به باکسِ شما یک پرسشِ ۶۰بایتی میفرستد که آدرسِ یک قربانی بهعنوانِ فرستنده در آن جعل شده؛ باکسِ شما هم مثلِ همیشه یک پاسخِ چندیندهبرابرِ بزرگتر به همان قربانی میفرستد. این کار را از چند هزار ریزالورِ باز همزمان انجام دهید و قربانی از اینترنت میافتد، بعد از آنکه سیلی دریافت کرده که بهنظر میرسد — دقیقاً، در سطحِ بسته — از سمتِ شما میآید. شما هدف نیستید. شما اسلحهاید، و ترافیکِ داخلِ گزارشِ حادثه از آنِ شماست.
چیزی که بعدش میآید هیچ جلوهای ندارد: abuse reportهایی از شبکههایی که اسمشان را هم نشنیدهاید، یک provider که آدرسِ شما را nullroute میکند تا ترانزیتِ خودش را حفظ کند، و یک گفتوگو دربارهٔ اکانتتان که ترجیح میدادید هرگز نداشته باشید. شما دقیقاً در طرفِ ایجادکنندهٔ همان اتفاقی قرار میگیرید که در راهنمای اولین ساعتِ حملهٔ DDoS ما توضیح داده شده، و هیچ نسخهای از آن داستان نیست که uptimeِ شما از آن جان سالم به در ببرد.
دو قفلِ مستقل جلوی این را میگیرند، و هر دو را میخواهید، چون هر کدام شکستِ آن دیگری را میپوشاند. اولی همان access-control خودِ Unbound است، که باید کلِ اینترنت را روی هر دو خانوادهٔ IP refuse کند و بعد صریحاً loopback و سابنتِ تونلِ شما را allow کند — یک فهرستِ default-deny، نه یک فهرستِ allow با یک دنبالهٔ سهلگیرانه. دومی این است که دیمن اصلاً کجا listen میکند: آن را به 127.0.0.1 و آدرسِ تونل بایند کنید، هرگز به 0.0.0.0، و پورتِ 53 را روی اینترفیسِ عمومی در فایروال بسته نگه دارید.
تله این است که فقط اولی را انجام دهید. یک قانونِ access-control پورت را ناپدید نمیکند؛ یک کوئریِ refuseشده هنوز یک بستهی دریافتشده و یک بستهی فرستادهشده است، آدرسِ شما همچنان در اسکنهایی که ریزالورهای باز را نقشهبرداری میکنند دیده میشود، و یک ویرایشِ بعدی روی بخشِ اشتباه یک refuse را به یک پاسخ تبدیل میکند. بایندکردن و فایروالگذاری این اشتباه را از نظرِ ساختاری غیرممکن میکنند، نه فقط یک خطِ کانفیگ دورتر. اگر باکس کانتینر هم اجرا میکند، پیش از آنکه فرض کنید قانونی که نوشتهاید همان قانونی است که در عمل اجرا میشود، دوباره چطور Docker پورتها را دورِ فایروالِ شما منتشر میکند را بخوانید.
پیشفرضهای Unbound معقولاند. خصوصی نیستند.
Unbound با تنظیماتی عرضه میشود که برای صحت و پایداری تیون شدهاند، که برای نرمافزاری که بیشتر توسطِ ISPها دیپلوی میشود همان پیشفرضِ درست است. یکدسته تنظیمات آن را به چیزی تبدیل میکند که برای همان شخصی ساخته شده که آن را اجرا میکند. هیچکدامشان عجیبوغریب نیستند؛ فقط از کارخانه خاموشاند، یا بینظرند.
دیگر به پرسشها دربارهٔ خودتان جواب ندهید. بهطورِ پیشفرض یک ریزالور با کمالِ میل نسخهٔ نرمافزار و hostnameِ خودش را از طریقِ کلاسِ CHAOS گزارش میدهد — version.bind و hostname.bind — که برای هر کسی که میخواهد تصمیم بگیرد باکسِ شما ارزشِ توجه دارد یا نه، شناساییِ رایگان است. hide-identity و hide-version هیچ هزینهای ندارند و یک fingerprint را حذف میکنند.
بسته خراب شوید، نه باز. اعتبارسنجیِ DNSSEC همان فرقِ بینِ ریزالوری است که یک پاسخِ جعلی را تشخیص میدهد و ریزالوری که همان پاسخ را serve میکند. harden-dnssec-stripped از پذیرفتنِ یک پاسخِ بدونِ امضا برای زونی که باید امضا شده باشد سر باز میزند، harden-glue و harden-below-nxdomain دو مسیرِ کلاسیکِ cache-poisoning را میبندند، و aggressive-nsec به ریزالور اجازه میدهد نامهای ناموجود را مستقیماً از رکوردهای denial کششده جواب دهد بهجای آنکه دوباره بپرسد. use-caps-for-id بزرگوکوچکیِ تصادفیِ حروف را بهعنوانِ آنتروپیِ اضافه در برابرِ spoofingِ کور اضافه میکند — ارزان است، و گاهی با یک سرورِ authoritativeِ بدساخت ناسازگار، که ارزش دارد پیش از آنکه یک بعدازظهر را روی دامنهای که resolve نمیشود تلف کنید بدانیدش.
هیچی را یادداشت نکنید. Unbound کوئریها را لاگ نمیکند مگر آنکه از آن خواسته شود، اما تنظیماتی که این کار را میکنند فقط یک خطِ بدونِ کامنت با شما فاصله دارند و بعضی پکیجهای توزیع پیشفرضِ پرحرفتری عرضه میکنند. verbosity: 0 را تنظیم کنید و صریحاً log-queries: no را بگویید، تا نیت در خودِ فایل دیده شود نه از غیابش استنباط شود. بعد این بخش را که یک تنظیم نیست بهیاد بیاورید: خودِ کش هم یک رکورد است. unbound-control dump_cache روی یک باکسِ درحالِاجرا تاریخچهٔ اخیرِ آنچه آن باکس جستجو کرده را چاپ میکند، و در حافظهٔ ماشینی زندگی میکند که دستهای یک نفرِ دیگر میتواند به آن برسد. خودش بهخودیخود منقضی میشود، که دلیلِ کاملِ اینکه عمرِ کوتاهِ کش و حریمِ خصوصی کمی در تناقضاند همین است، و همین هم دلیلِ اینکه نباید یک ریزالور را روی هاستی که اصلاً به آن اعتماد ندارید ماهها زنده نگه دارید.
عمداً کش کنید. هر پاسخی که از کش سرو میشود مشاهدهای است که هرگز در بالادست اتفاق نمیافتد، پس یک کشِ سالم هم یک قابلیتِ حریمِ خصوصی است، نه فقط یک قابلیتِ سرعت. prefetch رکوردهای پرطرفدار را پیش از منقضیشدن تازه میکند، پس حالتِ معمول اصلاً به شبکه دست نمیزند؛ serve-expired شما را وقتی یک سرورِ authoritative موقتاً غیرقابلدسترسی است آنلاین نگه میدارد. بالابردنِ cache-min-ttl سروصدای بالادست را بیشتر کم میکند، اما انتخابهای عمدیِ اپراتورهای دامنه را override میکند — TTLهای کوتاه همان چیزی است که CDNها و failover با آن کار میکنند — پس یک کفِ یک یا دو دقیقهای منطقی است و یک ساعت در نهایت شما را روی یک آدرسِ مرده گیر میاندازد.
دو راهِ ورود: تونل، یا DNS-over-TLS
دستگاههای شما باید یکجوری به ریزالور برسند، و انتخاب بینِ دو گزینهٔ معقول بیشتر یک سؤال است دربارهٔ اینکه چه چیزی را حاضرید منتشر کنید.
برای تقریباً همه، تونل جوابِ بهتری است. اگر لپتاپ و گوشیِ شما همین حالا هم یک نشستِ WireGuard به همان سرور دارند، ریزالور میتواند روی آدرسِ تونل listen کند و DNSِ معمولی را روی پورتِ 53 صحبت کند. ترافیک از قبل رمزنگاریشده و از قبل توسطِ تونل احرازهویتشده است، پس هیچ گواهیای برای گرفتن نیست، هیچ پورتِ تازهای رو به اینترنت باز نیست، هیچ پشتهی TLSای رو به غریبهها نیست، و — همان بخشِ کمارزشدیدهشده — هیچ hostnameای هیچجا نیست. راهنمای WireGuard در همین سایت کلاینتها را با DNS = 9.9.9.9 رها میکند، دقیقاً چون تا امروز چیزِ بهتری برای گذاشتن در آنجا نبود. حالا بهجایش این چیزی است که در آن خط میرود: آدرسِ تونلِ سرورِ خودتان.
DNS-over-TLS برای همان دستگاهی است که نمیتواند یک تونل نگه دارد. فیلدِ Private DNS اندروید قویترین دلیل برایش است — سراسرِ سیستم اعمال میشود، از ریاستارتها جان سالم به در میبرد، و اپهایی را هم پوشش میدهد که از راهِ دیگری نمیتوانید لمسشان کنید. هزینهاش یک hostname با یک گواهیِ معتبر است، و یک گواهی یعنی یک ثبتِ عمومی و دائمی در لاگهای Certificate Transparency که آن نام را به همان لحظهای که ساختینش گره میزند. بعد DNSِ passive همان نام را به آدرسِ سرور گره میزند. اگر کلِ هدفِ این تمرین دور نگهداشتنِ نامتان از زیرساخت بود، از یک hostname استفاده کنید که به هیچکجای نزدیکِ شما ختم نمیشود و آن را با همان دقتی که در ثبتِ ناشناسِ یک دامنه توضیح داده شده ثبت کنید — نه یک سابدامنه از همان دامنهای که برای همهچیزِ دیگر استفاده میکنید، که آن دو را برای همیشه به هم گره میزند.
یک هزینهٔ دومِ ظریفتر هم هست. یک اندپوینتِ DoT که گوشیهای در حالِ رومینگ میتوانند به آن برسند، نمیتواند با آدرسِ مبدأ محدود شود، پس، طبقِ تعریف، ریزالوری است که غریبهها هم میتوانند استفادهاش کنند اگر نامش را یاد بگیرند. این یک تقویتکننده نیست — TLS روی TCP به یک دستدهیِ کاملشده نیاز دارد، پس مبدأ نمیتواند جعل شود و چیزی برای بازتابدادن نیست — اما ظرفیتی است که دارید میبخشید، و سرویسی است که ارزشِ اسکنشدن را دارد. rate limitِ بهازای هر IP را روشن نگه دارید، یک hostname انتخاب کنید که کسی حدس نمیزند، و با آن مثلِ یک استثنای عمدی برای یک یا دو دستگاه رفتار کنید، نه یک درِ پیشفرض.
DNS-over-HTTPS گزینهٔ سومی است و اینجا معمولاً گزینهٔ غلط. به یک وبسرورِ جلوی ریزالور نیاز دارد، که یعنی قطعاتِ متحرکِ بیشتر و سطحِ حملهٔ بزرگتر برای همان یک فایده: غیرقابلتشخیصبودن از ترافیکِ وب. آن فایده وقتی قطعی است که میخواهید از یک شبکهای که DoT را مسدود کرده دور بزنید، و بیربط است وقتی اینطور نیست.
SP·07فیلترکردن یک محصولِ دیگر است؛ پیش از سوارکردنش تصمیم بگیرید
دیر یا زود یک نفر پیشنهاد میدهد blocklist اضافه کنید، و این پیشنهاد واقعاً جذاب است: فیلترکردن در سطحِ ریزالور همهٔ دستگاههای روی تونل را میپوشاند، از جمله تلویزیونِ هوشمند و اپهای گوشی که هیچ اکستنشنی به آنها نمیرسد. روی موبایل بهخصوص تنها جایی است که عملاً میشود مداخله کرد. همچنین همان قابلیتی است که بیشترین احتمال دارد بیسروصدا باعث شود به زیرساختِ خودتان بیاعتماد شوید، و ارزش دارد پیش از آنکه اتفاق بیفتد بفهمید چرا، نه در حینِ آن.
هزینهٔ اول این است که شکستها شبیهِ شکست نیستند. یک ریزالورِ خراب خودش را اعلام میکند؛ یک دامنهٔ بلاکشده بهشکلِ یک دکمهٔ پرداخت که هیچ کاری نمیکند، یک اپ که روی یک اسپینر گیر کرده، یک ایمیل که هرگز نمیرسد ظاهر میشود. علامت هفتهها بعد از نصبِ لیست، روی دستگاهی که اصلاً بهش فکر نمیکردید، ظاهر میشود، و هیچچیز آن را به تصمیمِ DNSای که یک ماهِ دیگر گرفته بودید ربط نمیدهد. هر blocklistی که نصب میکنید یک سیاست است که یک غریبه نوشته و بیسروصدا روی خانوارِ شما اجرا میشود. اگر یکی اضافه کردید، یادداشت کنید که این کار را کردهاید، آن را کوچک و معتبر نگه دارید، و یک راهِ یکدستوری برای خاموشکردنش داشته باشید — اولین قدمِ دیباگ برای هر چیزِ توضیحندادهٔ روی شبکهتان میشود "فیلتر را دور بزن و دوباره امتحان کن"، و آن قدم باید ارزان باشد.
هزینهٔ دوم این است که کاری را که آدمها امیدش را دارند نمیکند. یک اپلیکیشن با یک آدرسِ ریزالورِ hardcodeشده، یا یک کلاینتِ DoHِ خودش که داخلش compile شده، هیچوقت چیزی از ریزالورِ شما نمیپرسد؛ یک اتصال به یک IPِ hardcodeشده باز میکند و میرود. مرورگرها هم روزبهروز بیشتر روی DoHِ خودشان resolve میکنند مگر آنکه خلافش گفته شود. بلاککردنِ DNS یک لایهٔ بهداشتی است که بخشِ زیادی از نویزِ ردیابی و تبلیغاتِ کمزحمت را حذف میکند، و یک کنترلِ امنیتی نیست، چون هر چیزِ adversarial از قصد دورش میزند.
اگر بازهم میخواهیدش، یک local zoneِ کوچک در Unbound را به یک دیمنِ دوم ترجیح دهید — local-zone: "tracker.example." always_nxdomain نه به نرمافزارِ اضافه نیاز دارد، نه به یک web UI روی یک پورت که بعد باید از آن دفاع کنید، و نه به یک سرویسِ تازه که میتواند سقوط کند و resolveکردنِ نامِ شما را هم با خودش پایین بکشد. شرحِ وظایفِ ماشین را در یک خط نگه دارید: نامها را resolve میکند. هر مسئولیتِ اضافهای که به آن بدهید یک راهِ دیگر است برای اینکه همهچیز یکجا از کار بیفتد.
ریزالوری که خودتان اجرایش میکنید یک وابستگی است که خودتان مالکش هستید
وقتی وبسایتی که هاست میکنید از کار میافتد، بعضی آدمها نمیتوانند چیزی را بخوانند. وقتی ریزالورِ شما از کار میافتد، هیچی کار نمیکند — نه مرورگر، نه ایمیل، نه package manager، نه همان اپی که قرار بود به شما بگوید سرور خراب است. این باریترین سرویسی است که میتوانید روی یک باکسِ ارزان بگذارید، و به شکلهایی خراب میشود که شبیهِ DNS نیستند.
ارزش دارد از قبل حالتهای واقعبینانهٔ شکست را بدانید، چون هرکدام امضای متفاوتی دارد. VPS ریاستارت میشود و Unbound هیچوقت در بوت فعال نشده بود، پس همهچیز کار میکند تا اولین ریاستارتِ برنامهریزینشده. یک blocklistِ بزرگ کش را روی یک اینستنسِ ۱ گیگابایتی به swap میراند و OOM killer همان ریزالور را انتخاب میکند. یک زون در یکجایی امضاهای DNSSECِ خودش را میشکند، و ریزالورِ درستپیکربندیشدهٔ شما پاسخ را رد میکند درحالیکه هر کسی که روی یک ریزالورِ بدونِ اعتبارسنجی است همچنان مرورش میکند — باکسِ شما درست میگوید و سایت همچنان بهنظرِ شما خراب میآید، که اگر یادتان رفته باشد اعتبارسنجی میکنید پنج دقیقهٔ گیجکنندهای میشود. یا تونل قطع میشود، و چون DNS = 10.66.0.1 فقط داخلِ تونل وجود دارد، دستگاه اصلاً هیچ ریزالوری ندارد و گزارش میدهد که آفلاین است.
خوشبختانه راهحلها ارزاناند. سرویس را در بوت فعال کنید و واقعاً با یک ریاستارت تستش کنید نه اینکه فقط فرض کنید. به کلاینتها یک ریزالورِ ثانویه بدهید تا یک تونلِ مرده بهجای متوقفشدن فقط افت کند — یک ریزالورِ عمومی در آن جایخالی یک مصالحهٔ کوچک و صریح در حریمِ خصوصی است که فقط وقتی ریزالورِ خودتان غیرقابلدسترسی است اعمال میشود، و معمولاً معاملهٔ درستی است. serve-expired را روشن نگه دارید تا یک قطعیِ کوتاهِ بالادست، قطعیِ خودِ شما نشود. ریزالور را از یکجای دیگر چک کنید، نه از خودِ ماشین، که تنها راه برای فهمیدنِ فرقِ بینِ "خراب" و "غیرقابلدسترسی" همین است.
و یک کپی از کانفیگ نگه دارید. کلِ ماجرا چند ده خط است که یک بعدازظهر وقتتان را گرفت تا درستش کنید و یک سال دیگر یادتان نمیآید؛ جایش در همان بکآپهای رمزنگاریشده و خارج از سرورِ شما، کنارِ کلیدهای WireGuard است، تا بازسازیاش بیست دقیقه باشد نه یک بعدازظهرِ دوم. این همان خلاصهٔ صادقانهٔ کلِ این تمرین است: یک باکسِ کوچک که یک کار را انجام میدهد، به قیمتِ ارزانترین پلنِ فهرست، که یک وعده دربارهٔ نگهداری را با چینشی جایگزین میکند که در آن رکورد اصلاً هیچوقت ساخته نمیشود.
SP·09گامبهگام
-
01
شروع از یک باکسی که از قبل سختسازی شده
یک ریزالور یک سرویسِ کوچک و ساکت است، که همین وسوسهانگیزش میکند روی هر چیزی که دمدست است نصبش کنید. این کار را نکنید — این باکس هر نامی را که هر دستگاهِ روی تونلِ شما جستجو میکند خواهد دید، پس همان رفتاری را سزاوار است که هر چیزِ دیگرِ نگهدارندهٔ رازها سزاوارش است. کوچکترین پلنی را که دوست دارید دیپلوی کنید؛ ۱ گیگابایت RAM برای یک خانوار کاملاً کافی است، چون اندازههای کشِ زیر بر حسبِ دهها مگابایت اندازهگیری میشوند. پیش از هر چیزِ دیگر، اولین ساعت پس از دیپلوی را کامل انجام دهید: یک کاربرِ نامدار، SSHِ فقط-با-کلید، default-deny روی هر دو خانوادهٔ IP، بهروزرسانیهای امنیتیِ خودکار.
بعد Unbound را نصب کنید. پکیجِ توزیع root hints و لنگرِ اعتمادِ ریشهٔ DNSSEC را همراهش میآورد و rolloverِ خودکارِ همان لنگر را هم سیمکشی میکند، که یکی از همان معدود موقعیتهایی است که نسخهٔ پکیجشده واقعاً شما را از یک دسته خرابیِ آینده نجات میدهد.
sudo apt update && sudo apt install -y unbound dnsutils unbound -V | head -n 3 # the packaged trust anchor the resolver will validate against sudo ls -l /var/lib/unbound/root.key
اگر
root.keyوجود ندارد، پکیجِ شماunbound-anchorرا اجرا نکرده و اعتبارسنجی روی همهچیز بسته خراب میشود. پیش از ادامه، یکبار آن را باsudo -u unbound unbound-anchor -a /var/lib/unbound/root.keyبسازید. -
02
پورتِ 53 را از systemd-resolved پس بگیرید
روی بیشترِ توزیعهای امروزی، چیزی از قبل صاحبِ پورتِ 53 است:
systemd-resolvedیک stub listener روی127.0.0.53اجرا میکند، و/etc/resolv.confیک symlink است که به آن اشاره میکند. Unbound از شروعشدن سر باز میزند، یا شروع میشود اما هیچ چیزِ مفیدی را بایند نمیکند، تا وقتی این حل شود. پیش از ویرایش، نگاه کنید.ss -ulpn 'sport = :53' ls -l /etc/resolv.conf
پیش از اجرای بلوکِ بعدی این پاراگراف را بخوانید: بینِ غیرفعالکردنِ stub و شروعکردنِ Unbound، این ماشین اصلاً هیچ DNSِ کارکنندهای ندارد. مرحلههای ۳ و ۴ را در همان یک نشست تمام کنید، و پیش از آن یک عملیاتِ
aptرا در یک پنجرهٔ دیگر شروع نکنید — روی یک جستجوی نام هنگ میکند و شما اشتباهاً فکر میکنید مشکل از همان ریزالوری است که هنوز اجرایش نکردهاید.# stop resolved from holding the port (appends inside the [Resolve] section) printf 'DNSStubListener=no\n' | sudo tee -a /etc/systemd/resolved.conf sudo systemctl restart systemd-resolved # point the host at the resolver it is about to run sudo rm -f /etc/resolv.conf printf 'nameserver 127.0.0.1\noptions edns0 trust-ad\n' | sudo tee /etc/resolv.conf # the port should now be free ss -ulpn 'sport = :53'
-
03
یک کانفیگ بنویسید که بازگشتی کار میکند و فراموش میکند
کانفیگِ پکیجشده را دستنخورده بگذارید و فایلِ خودتان را در drop-in directory اضافه کنید، تا یک آپگرِیدِ پکیج هیچوقت بیسروصدا تصمیمهای شما را برنگرداند. هر خطِ زیر یا دربارهٔ رد کردنِ غریبههاست، یا بازگشتیکردن از ریشه، یا نگهنداشتنِ رکورد. اگر آدرسِ تونل و سابنتِ سرورِ WireGuardِ خودتان فرق دارد،
10.66.0.1و10.66.0.0/24را با آنها جایگزین کنید.sudo tee /etc/unbound/unbound.conf.d/private-resolver.conf > /dev/null <<'EOF' server: # listen for the host itself and for the tunnel — never on 0.0.0.0 interface: 127.0.0.1 interface: 10.66.0.1 port: 53 # default-deny: refuse the internet, then allow what you trust access-control: 0.0.0.0/0 refuse access-control: ::/0 refuse access-control: 127.0.0.0/8 allow access-control: 10.66.0.0/24 allow # recurse from the root and send each server only the label it needs qname-minimisation: yes harden-dnssec-stripped: yes harden-below-nxdomain: yes harden-glue: yes aggressive-nsec: yes use-caps-for-id: yes # answer nothing about the software or the host hide-identity: yes hide-version: yes # keep no query log, and say little to the journal verbosity: 0 log-queries: no log-replies: no # a warm cache is an upstream observation that never happens cache-min-ttl: 120 cache-max-ttl: 86400 prefetch: yes prefetch-key: yes serve-expired: yes # belt and braces if a rule above is ever loosened ratelimit: 1000 ip-ratelimit: 100 # sizing for a small instance num-threads: 2 so-reuseport: yes msg-cache-size: 32m rrset-cache-size: 64m EOFبه همان چیزی که در فایل نیست توجه کنید: هیچ
forward-zoneای وجود ندارد. همین غیابش است که این را یک ریزالورِ بازگشتی میکند بهجای یک کشِ جلوی ریزالورِ یک نفرِ دیگر. اگر بعداً یک قطعهکد از یک آموزش پیست کنید که یکی اضافه میکند، بیسروصدا کلِ هدفِ این تمرین را نقض کردهاید. -
04
آن را اجرا کنید، بعد ثابت کنید DNSSEC واقعاً اعتبارسنجی میکند
پیش از ریاستارتِ هر چیزی، سینتکس را چک کنید — روی باکسی که
resolv.confخودش الان به Unbound اشاره میکند، یک خطای کانفیگ یعنی هیچ resolveکردنِ نامی درحالیکه مشغولِ دیباگش هستید.sudo unbound-checkconf sudo systemctl enable --now unbound systemctl --no-pager status unbound | head -n 5
حالا آن دو رفتاری را که اهمیت دارند تأیید کنید، چون یک ریزالوری که پاسخ میدهد با یک ریزالوری که اعتبارسنجی میکند یکی نیست. یک نامِ امضاشده باید با فلگِ
adبرگردد — authenticated data — و یک نام با امضاهایی که عمداً خراب شدهاند باید بهجایِ resolveشدن، بسته خراب شود باSERVFAIL.# should show: flags: qr rd ra ad dig @127.0.0.1 example.com +dnssec | grep -E '^;; flags' # should show: status: SERVFAIL (not NOERROR, not an address) dig @127.0.0.1 dnssec-failed.org | grep -E '^;; ->>HEADER' # and a normal name should simply work dig @127.0.0.1 +short cloudflare.com
اگر زونِ خراب به یک آدرس resolve شد، اعتبارسنجی درحالِ اجرا نیست: چک کنید
/var/lib/unbound/root.keyوجود دارد و توسطِ کاربرِunboundقابلخواندن است. اگر همهچیزSERVFAILاست، دلیلِ معمول یک ساعتِ بهشدت غلط است — امضاها بازهٔ اعتبار دارند، و باکسی که چند ساعت ناهماهنگ است کلِ اینترنت را رد میکند. -
05
درِ عمومی را ببندید، فقط تونل را باز بگذارید
کانفیگ از قبل هم غریبهها را رد میکند. این مرحله کاری میکند که از اول هیچچیزی برای رسیدنِ یک غریبه وجود نداشته باشد — دومین قفل از آن دو قفل، همان قفلی که از یک ویرایشِ آینده روی اولی جان سالم به در میبرد.
# DNS is reachable from the tunnel interface only sudo ufw allow in on wg0 to any port 53 proto udp sudo ufw allow in on wg0 to any port 53 proto tcp sudo ufw status verbose
بعد آن را با تنها روشی که بهحساب میآید تأیید کنید، از یک ماشینِ دیگر. تستکردن از خودِ سرور اصلاً هیچچیزی را ثابت نمیکند — loopback عمداً مجاز است. این کار را از لپتاپِ خودتان وقتی تونل پایین است، یا از هر هاستِ دیگری که دارید، انجام دهید.
# must time out. an answer here means you are running an open resolver. dig @SERVER_PUBLIC_IP example.com +time=3 +tries=1 # same question over IPv6, which is the half people forget dig -6 @SERVER_IPV6 example.com +time=3 +tries=1
اگر هرکدام جوابی برگرداند، همین الان متوقف شوید و درستش کنید، نه بعد از abuse report. دلیلهای معمول یک
interface: 0.0.0.0است که از یک کانفیگِ پکیجشده باقی مانده، یک قانونِ فایروال که از یک آزمایشِ قبلی 53 را بهطورِ سراسری مجاز کرده، یا Dockerی که یک پورتِ کانتینر را منتشر میکند و کلاً ازufwدور میزند. -
06
دستگاههای خودتان را بهسمتِ آن نشانه بگیرید
روی سمتِ کلاینت این یک تغییرِ یکخطی است. در کانفیگِ کلاینتِ WireGuard، خطِ
DNSبهجای یک ریزالورِ عمومی، آدرسِ تونلِ سرورِ خودتان میشود — این همان ویرایشی است کهDNS = 9.9.9.9را از راهنمای WireGuard بازنشسته میکند.[Interface] PrivateKey = <paste client.key> Address = 10.66.0.2/32, fd86:ea04:1115::2/128 DNS = 10.66.0.1 [Peer] PublicKey = <paste server.pub> Endpoint = YOUR_SERVER_IP:51820 AllowedIPs = 0.0.0.0/0, ::/0 PersistentKeepalive = 25
تونل را بالا بیاورید و از سمتِ کلاینت دو چیزِ جدا را تأیید کنید: اینکه پاسخها از ریزالورِ شما میآیند، و اینکه بازگشت واقعاً از VPSِ شما خارج میشود نه از یکجایِ دیگر. چکِ دوم همان چکِ مفید است —
whoami.akamai.netآدرسِ هر ریزالوری که پرسیده را برمیگرداند، پس باید فقط IPِ عمومیِ سرورِ شما را چاپ کند و هیچ چیزِ دیگری را.# answers should come from the tunnel address dig example.com | grep -E 'SERVER:' # should print your VPS public IP — this is the leak test dig +short whoami.akamai.net # and the ad flag should still be there, end to end dig example.com +dnssec | grep -E '^;; flags'
-
07
DNS-over-TLS را فقط برای دستگاهی اضافه کنید که نمیتواند تونل نگه دارد
این مرحله را رد کنید مگر آنکه یک دستگاهِ مشخص داشته باشید — معمولاً یک گوشیِ اندروید، از طریقِ تنظیمِ سراسریِ Private DNSاش — که میخواهید بدونِ یک تونلِ دائمی پوشش داده شود. این کار به یک hostname و یک گواهی نیاز دارد، و آن hostname یک رکوردِ عمومیِ دائمی در لاگهای Certificate Transparency میشود، پس یکی را انتخاب کنید که به هیچکدام از هویتهای دیگرِ شما نزدیک نمیشود.
sudo apt install -y certbot sudo ufw allow 80/tcp comment 'certbot, temporarily' sudo certbot certonly --standalone -d dns.example.net sudo ufw delete allow 80/tcp # unbound must be able to read the key sudo usermod -a -G ssl-cert unbound 2>/dev/null || true sudo chgrp -R ssl-cert /etc/letsencrypt/live /etc/letsencrypt/archive sudo chmod -R g+rX /etc/letsencrypt/live /etc/letsencrypt/archive
listenerِ TLS را بهصورتِ فایلِ drop-inِ جداگانهٔ خودش اضافه کنید، تا اگر نظرتان عوض شد بتوانید آن را با یک حرکت حذف کنید.
# NOTE: drop-in files are read in alphabetical order and the last # access-control line for a given prefix wins — so this file must # sort AFTER private-resolver.conf, or its refuse rule overrides # the allow below and every DoT client gets REFUSED. sudo tee /etc/unbound/unbound.conf.d/zz-dot.conf > /dev/null <<'EOF' server: interface: 0.0.0.0@853 interface: ::0@853 tls-service-key: "/etc/letsencrypt/live/dns.example.net/privkey.pem" tls-service-pem: "/etc/letsencrypt/live/dns.example.net/fullchain.pem" # roaming clients have no fixed address, so this endpoint must accept any. # safe only because port 53 stays bound to loopback + wg0 and blocked at # the firewall — TLS over TCP cannot be spoofed, so it cannot be reflected. access-control: 0.0.0.0/0 allow access-control: ::/0 allow EOF sudo ufw allow 853/tcp sudo unbound-checkconf && sudo systemctl restart unboundپیش از آنکه به آن اعتماد کنید، از بیرونِ تونل تستش کنید، بعد hostname را در فیلدِ Private DNSِ گوشی بگذارید. تمدید همان بخشی است که سه ماه بعد بیسروصدا خراب میشود — certbot گواهی را جایگزین میکند اما Unbound همچنان قدیمی را در حافظه نگه میدارد، پس یک deploy hook اضافه کنید که آن را reload کند.
kdig -d @dns.example.net +tls-ca +tls-host=dns.example.net example.com echo 'systemctl reload unbound' | sudo tee /etc/letsencrypt/renewal-hooks/deploy/unbound.sh sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/unbound.sh


