کتابخانه‌ی استاندارد · شبکه

دی‌اوه‌اچ net.doh

DNS رمزشده: یک حل‌کننده روی DNS روی HTTPS و DNS روی TLS با جایگزینی کارگزار و حافظه‌ی TTL، DNS ساده‌ی UDP به عنوان جایگزین، پیش‌تنظیم‌ها و یک کارگزار محلی برای برنامه‌های دیگر.

واردسازی شبکه.دی‌اوه‌اچ

نام آرگومان‌ها شناسه‌ی خود کد است و معادل فارسی ندارد؛ گونه‌ها، کلیدواژه‌ها و نام بسته‌ها با معادل فارسی نوشته می‌شوند.

DNS معمولی «نشانی این نام چیست؟» را به متن ساده روی UDP می‌پرسد، پس شبکه‌ی میان شما و حل‌کننده هر نامی را که جستجو می‌کنید می‌خواند و می‌تواند پاسخ را عوض یا مسدود کند. DNS روی HTTPS (DoH) و DNS روی TLS (DoT) همین پرسش را درون یک اتصال رمزشده می‌فرستند. این بسته هر دو را پشتیبانی می‌کند، و DNS ساده‌ی UDP را هم، و آنچه برنامه روی آن لازم دارد اضافه می‌کند: یک حل‌کننده که فهرستی از کارگزارها را به ترتیب امتحان می‌کند، پاسخ‌ها را به اندازه‌ی TTL‌شان به یاد می‌سپارد و جستجوی میزبان را با فهرستی از نشانی‌ها پاسخ می‌دهد. یک کارگزار محلی حل‌کننده را به یک کارگزار DNS محلی کوچک تبدیل می‌کند، تا برنامه‌های دیگر با اشاره دادن DNS‌شان به آن از آن استفاده کنند. برای دیدن اینکه تکه‌ها در یک برنامه چگونه کنار هم می‌نشینند، ساختن برنامه‌ای به سبک v2ray یا VPN را بخوانید.

ایده‌های اصلی:

  • یک کارگزار می‌گوید چگونه به یک کارگزار DNS برسیم: نوع دی‌اوه‌اچ پست (POST روی HTTPS)، نوع دی‌اوه‌اچ گت (GET روی HTTPS)، نوع دی‌اوه‌تی (TLS روی درگاه ۸۵۳) یا نوع یو دی پی ساده (ساده). کلودفلر، گوگل، کواد نه و شکل‌های DoT‌شان آماده‌اند و کارگزار جدید، کارگزار دی‌اوه‌تی جدید و کارگزار ساده جدید مال خودتان را می‌سازند.
  • نشانی‌های IP یک کارگزار را در نشانی‌های راه‌انداز بدهید. آن‌وقت برنامه لازم ندارد نام خود کارگزار را از پیش حل کند، که وقتی دقیقا DNS مسدود است اهمیت دارد.
  • پرسش یک بار از یک کارگزار می‌پرسد. حل‌کننده جدید و حل از یک فهرست می‌پرسند: کارگزاری که شکست بخورد، مهلتش تمام شود یا SERVFAIL یا REFUSED بدهد برای بعدی کنار گذاشته می‌شود و پاسخ‌ها نگه داشته می‌شوند (پاسخ به اندازه‌ی TTL‌ش، بین حدهای تعیین حدود ماندگاری؛ پاسخ «چنین نامی نیست» برای زمان ثابتی کوتاه).
  • گواهی‌ها بررسی می‌شوند. ناامن آن را فقط برای آزمون خاموش می‌کند.

چیزهایی که آدم را گیر می‌اندازد:

  • DNS رمزشده پرسش را از شبکه پنهان می‌کند، نه از حل‌کننده. حل‌کننده‌ای که برمی‌گزینید هر نامی را که جستجو می‌کنید می‌بیند. یکی را برگزینید که به آن اعتماد دارید و به یاد داشته باشید که وصل شدن به نشانی یک حل‌کننده‌ی معروف خودش دیده می‌شود.
  • حل‌کننده‌های مسدود. شبکه می‌تواند نشانی کارگزارهای DoH عمومی را ببندد. چند کارگزار به کار ببرید، یک کارگزار ساده یا خصوصی را آخر فهرست نگه دارید و برای کارگزارهای ساده‌ی رایج در ایران کارگزارهای ساده ایران را ببینید. DNS ساده خواناست و سر راه قابل تغییر است.
  • DNSSEC نیست. پاسخ‌ها همان‌طور که کارگزار داد پذیرفته می‌شوند؛ هیچ چیزی اینجا امضای DNSSEC را بررسی نمی‌کند.
  • کارگزار محلی روی UDP و TCP پاسخ می‌دهد (همان درگاه، TCP با پیشوند طول دو بایتی) و کنترل دسترسی ندارد. وقتی میزبان خالی است روی 127.0.0.1 گوش می‌دهد؛ 0.0.0.0 را فقط عمداً بدهید چون سرور DNS باز روی نشانی عمومی سوءاستفاده می‌شود.
  • آنچه نگه داشته‌اید آزاد کنید. آزاد کردن پاسخ، آزاد کردن پاسخ نهایی و آزاد کردن کارگزارها حافظه را آزاد می‌کنند؛ حل‌کننده و کارگزار محلی تا پایان برنامه زنده می‌مانند.
  • حافظه و شمارنده‌ها میان نخ‌ها مشترک‌اند و حل‌کننده قفل خودش را دارد، پس یک حل‌کننده می‌تواند به چند نخ سرویس بدهد.
  • کارگزارهای IPv6 کار می‌کنند. نشانی کارگزار می‌تواند IPv6 باشد، روی UDP، TLS یا HTTPS. کارگزارهای آماده نخست IPv4 را دارند؛ با نشانی آی‌پی۶، کلودفلر آی‌پی۶، گوگل آی‌پی۶ و کواد نه آی‌پی۶ نشانی‌های IPv6 را می‌افزایند یا به کار می‌برند (2606:4700:4700::1111، 2001:4860:4860::8888، 2620:fe::fe). کارگزار محلی می‌تواند روی ::1 یا :: گوش دهد.
  • اتصال‌ها بازاستفاده می‌شوند. DoH روی HTTPS اتصال‌هایش را زنده نگه می‌دارد و برای پرس‌وجوهای بعدی دوباره به کار می‌برد (تا ۸ اتصال بی‌کار، ۳۰ ثانیه)؛ اتصال کهنه با اتصال تازه عوض و پرس‌وجو یک بار تکرار می‌شود. اتصال‌های بازاستفاده‌شده شمار بازاستفاده‌ها را می‌دهد و بستن اتصال‌های بی‌کار اتصال‌های بی‌کار را می‌بندد.
  • پیش‌تنظیم‌های ایران تأییدنشده‌اند. نشانی‌های شکن، چهارصدوسه، الکترو، رادار و بگزر از فهرست‌های جامعه آمده و با سایت رسمی آن سرویس‌ها تأیید نشد. پیش از اتکا بررسی‌شان کنید.

استفاده از حل‌کننده

از فهرستی از کارگزارها یک حل‌کننده بسازید و از آن بپرسید. جستجوی دوم همان نام از حافظه می‌آید و به شبکه دست نمی‌زند. نمونه یک کارگزار DNS کوچک روی loopback به کار می‌برد تا هرجا اجرا شود؛ با کارگزارهای واقعی از کارگزارهای پیش‌فرض یا فهرست خودتان استفاده کنید.

net-doh-guide-resolver.salam
// زبان: فارسی
واردسازی فشرده سازی
واردسازی حافظه
واردسازی شبکه.دی‌ان‌اس
واردسازی شبکه.دی‌اوه‌اچ
واردسازی شبکه.یو دی پی
واردسازی همگام سازی

ناپایا udp_port := 0
ناپایا queries := 0
ناپایا ready := همگام سازی.گروه انتظار جدید()

تابع record(name: رشته، rtype: صحیح، ttl: صحیح، data: رشته): دی‌ان‌اس.رکورد:
    برگشت دی‌ان‌اس.رکورد { نام دامنه = name، نوع رکورد = rtype، رده = 1، زمان ماندگاری = ttl، داده = data }
پایان

تابع answer_for(p: تهی*، n: صحیح): فشرده سازی.بافر بایت:
    queries++
    question := دی‌ان‌اس.کدگشایی(p، n)
    asked := question.پرسش‌ها.پرسش‌ها.بگیر(0)
    ناپایا records := وکتور {} برگردان وکتور<دی‌ان‌اس.رکورد>
    ناپایا rcode := 0
    اگر asked.نام دامنه برابر "a.test" و asked.نوع رکورد برابر دی‌ان‌اس.نوع آ:
        records.بیفزا(record("a.test"، دی‌ان‌اس.نوع آ، 120، "10.0.0.1"))
        records.بیفزا(record("a.test"، دی‌ان‌اس.نوع آ، 300، "10.0.0.2"))
    وگرنه asked.نام دامنه برابر "v6.test" و asked.نوع رکورد برابر دی‌ان‌اس.نوع کواداِی:
        records.بیفزا(record("v6.test"، دی‌ان‌اس.نوع کواداِی، 300، "2001:db8::5"))
    وگرنه asked.نام دامنه برابر "txt.test" و asked.نوع رکورد برابر دی‌ان‌اس.نوع تی‌ایکس‌تی:
        records.بیفزا(record("txt.test"، دی‌ان‌اس.نوع تی‌ایکس‌تی، 60، "hello world"))
    وگرنه asked.نام دامنه برابر "alias.test":
        records.بیفزا(record("alias.test"، دی‌ان‌اس.نوع سی‌نیم، 60، "target.test"))
        اگر asked.نوع رکورد برابر دی‌ان‌اس.نوع آ:
            records.بیفزا(record("target.test"، دی‌ان‌اس.نوع آ، 60، "10.9.9.9"))
        پایان
    وگرنه:
        rcode = 3
    پایان
    برگشت دی‌اوه‌اچ.کدگذاری پاسخ(question.شناسه، asked.نام دامنه، asked.نوع رکورد، rcode، records)
پایان

تابع udp_server():
    s := یو دی پی.پیوند(0)
    udp_port = یو دی پی.درگاه(s)
    همگام سازی.اتمام(ready)
    buf := حافظه.تخصیص(2048 برگردان طبیعی۶۴)
    ناپایا from_host := ""
    ناپایا from_port := 0
    تا درست:
        n := یو دی پی.دریافت بایت(s، buf، 2048، from_host، from_port)
        اگر n بزرگتر 0:
            answer := answer_for(buf، n)
            یو دی پی.ارسال بایت(s، from_host، from_port، answer.داده، answer.طول)
        پایان
    پایان
پایان

تابع start_mock():
    همگام سازی.افزودن(ready، 1 برگردان صحیح۶۴)
    _t := نخ‌ساز(udp_server)
    همگام سازی.انتظار(ready)
پایان

تابع mock_server(name: رشته): دی‌اوه‌اچ.کارگزار:
    ناپایا server := دی‌اوه‌اچ.کارگزار ساده جدید(name، "127.0.0.1")
    server.درگاه = udp_port
    برگشت server
پایان

تابع ریشه:
    start_mock()
    ناپایا servers := وکتور {} برگردان وکتور<دی‌اوه‌اچ.کارگزار>
    servers.بیفزا(mock_server("mock"))
    resolver := دی‌اوه‌اچ.حل‌کننده جدید(servers)

    addresses := دی‌اوه‌اچ.جستجوی میزبان(resolver، "a.test")
    سرچاپ "نشانی‌ها:"، addresses.طول()، addresses.بگیر(0)
    again := دی‌اوه‌اچ.جستجوی میزبان(resolver، "a.test")
    سرچاپ again.طول()
    stats := دی‌اوه‌اچ.آمار(resolver)
    سرچاپ "از سرور"، queries، "بار پرسیده شد؛ برخورد حافظه:"، stats.برخورد حافظه
پایان
خروجینشانی‌ها: 2 10.0.0.1 2 از سرور 1 بار پرسیده شد؛ برخورد حافظه: 1

برای کار واقعی کارگزارها را به ترتیب اعتمادتان بگذارید و به هر کدام نشانی‌هایش را بدهید:

ناپایا servers := وکتور {} برگردان وکتور<دی‌اوه‌اچ.کارگزار>
servers.بیفزا(دی‌اوه‌اچ.کلودفلر())
servers.بیفزا(دی‌اوه‌اچ.گوگل دی‌اوه‌تی())
servers.بیفزا(دی‌اوه‌اچ.کارگزار ساده جدید("home"، "192.168.1.1"))
resolver := دی‌اوه‌اچ.حل‌کننده جدید(servers)
سرچاپ دی‌اوه‌اچ.جستجوی میزبان(resolver، "example.com")

DNS وقتی شبکه‌ها دخالت می‌کنند

سه نوع دردسر رایج است. شبکه می‌تواند جستجوهای شما را بخواند: DoH یا DoT به کار ببرید. می‌تواند پاسخ بعضی نام‌ها را عوض کند یا چیزی برنگرداند: DNS رمزشده تغییر سر راه را می‌بندد ولی مسدود کردن نشانی حل‌کننده را نه. می‌تواند خود حل‌کننده‌ها را مسدود کند: چند تا فهرست کنید، نشانی‌های راه‌انداز را پر نگه دارید تا برای رسیدن به آن‌ها جستجویی لازم نباشد و کارگزار ساده‌ای را که در شبکه‌ی شما کار می‌کند آخرین انتخاب بگذارید. کارگزارهای ساده ایران کارگزارهای ساده‌ی رایج در ایران را فهرست می‌کند؛ ترافیکشان رمزشده نیست.

یک کارگزار محلی روی 127.0.0.1 راه بیندازید و سیستم‌عامل یا یک برنامه را به آن اشاره بدهید، تا هر جستجویی که می‌کند از حل‌کننده‌ی شما و حافظه‌اش بگذرد. وقتی برنامه خودش از راه پراکسی نام‌ها را جستجو می‌کند، همان‌طور که SOCKS5 و تروجان می‌کنند، بگذارید پراکسی نام را حل کند تا جستجو اصلا محلی انجام نشود.

چه باید دانست

  • DNS رمزشده پرسش را از شبکه پنهان می‌کند، نه از حل‌کننده‌ای که برمی‌گزینید.
  • نشانی‌های راه‌انداز را پر کنید، یا با تعیین کارگزارهای راه‌انداز یک راه‌انداز بگذارید، تا حل‌کننده برای پیدا کردن DNS‌ش به DNS نیاز نداشته باشد.
  • کارگزارهای ناموفق کنار گذاشته می‌شوند؛ پاسخ «چنین نامی نیست» نهایی است و برای زمان کوتاه شکست نگه داشته می‌شود.
  • اعتبارسنجی DNSSEC نیست. کارگزار محلی کنترل دسترسی ندارد؛ آن را به loopback ببندید.
  • پرسش مهلتی به میلی‌ثانیه دارد و حل‌کننده تعیین مهلت؛ آن را کوتاه نگه دارید تا یک کارگزار مسدود برنامه‌تان را معطل نکند.
  • هیچ گزارشی خودکار نوشته نمی‌شود.

گونه‌ها

ورودی حافظه CacheEntry

ساختار ورودی حافظه
یک پاسخ نگه‌داری‌شده: بایت‌ها، زمان انقضا و اینکه شکست نگه‌داری‌شده است یا نه.
نامانگلیسیگونهتوضیح
پاسخ خامrawفشرده سازی.بافر بایتپاسخ نگه‌داری‌شده به شکل بایت‌های سیمی DNS.
زمان انقضاexpires_msصحیح۶۴ = 0زمان انقضای ورودی، به شکل زمانی به میلی‌ثانیه.
منفیnegativeمنطقی = نادرستدرست برای پاسخ نگه‌داری‌شده‌ی «چنین نامی نیست» یا «داده‌ای نیست».

پاسخ نهایی Answer

ساختار پاسخ نهایی
آنچه حل برمی‌گرداند: پاسخ، و اینکه از حافظه آمد یا نه.
نامانگلیسیگونهتوضیح
معتبرokمنطقی = نادرستدرست وقتی کارگزاری پاسخ قابل استفاده داد، یا حافظه داد.
از حافظهcachedمنطقی = نادرستدرست وقتی پاسخ از حافظه آمد بی‌آنکه از کارگزاری پرسیده شود.
منفیnegativeمنطقی = نادرستدرست وقتی پاسخ می‌گوید نام وجود ندارد یا داده‌ای از آن نوع ندارد.
کد نتیجهrcodeصحیح = 0کد پاسخ DNS: ۰ موفق، ۳ نامی که وجود ندارد.
زمان ماندگاریttlصحیح = 0پاسخ چند ثانیه دیگر می‌تواند استفاده شود، پس از حدهای تعیین حدود ماندگاری.
پاسخ خامrawفشرده سازی.بافر بایتپاسخ به شکل بایت‌های سیمی DNS. با آزاد کردن پاسخ نهایی آزادش کنید.
پیامmsgدی‌ان‌اس.پیامdns.Message رمزگشایی‌شده.
کارگزارserverرشته = ""نام کارگزاری که پاسخ داد، برای پاسخ حافظه خالی.
خطاerrرشته = ""چرا هیچ کارگزاری نتوانست پاسخ دهد، وقتی معتبر نادرست است.
net-doh-Resolver.salam
// زبان: فارسی
واردسازی فشرده سازی
واردسازی حافظه
واردسازی شبکه.دی‌ان‌اس
واردسازی شبکه.دی‌اوه‌اچ
واردسازی شبکه.یو دی پی
واردسازی همگام سازی

ناپایا udp_port := 0
ناپایا queries := 0
ناپایا ready := همگام سازی.گروه انتظار جدید()

تابع record(name: رشته، rtype: صحیح، ttl: صحیح، data: رشته): دی‌ان‌اس.رکورد:
    برگشت دی‌ان‌اس.رکورد { نام دامنه = name، نوع رکورد = rtype، رده = 1، زمان ماندگاری = ttl، داده = data }
پایان

تابع answer_for(p: تهی*، n: صحیح): فشرده سازی.بافر بایت:
    queries++
    question := دی‌ان‌اس.کدگشایی(p، n)
    asked := question.پرسش‌ها.پرسش‌ها.بگیر(0)
    ناپایا records := وکتور {} برگردان وکتور<دی‌ان‌اس.رکورد>
    ناپایا rcode := 0
    اگر asked.نام دامنه برابر "a.test" و asked.نوع رکورد برابر دی‌ان‌اس.نوع آ:
        records.بیفزا(record("a.test"، دی‌ان‌اس.نوع آ، 120، "10.0.0.1"))
        records.بیفزا(record("a.test"، دی‌ان‌اس.نوع آ، 300، "10.0.0.2"))
    وگرنه asked.نام دامنه برابر "v6.test" و asked.نوع رکورد برابر دی‌ان‌اس.نوع کواداِی:
        records.بیفزا(record("v6.test"، دی‌ان‌اس.نوع کواداِی، 300، "2001:db8::5"))
    وگرنه asked.نام دامنه برابر "txt.test" و asked.نوع رکورد برابر دی‌ان‌اس.نوع تی‌ایکس‌تی:
        records.بیفزا(record("txt.test"، دی‌ان‌اس.نوع تی‌ایکس‌تی، 60، "hello world"))
    وگرنه asked.نام دامنه برابر "alias.test":
        records.بیفزا(record("alias.test"، دی‌ان‌اس.نوع سی‌نیم، 60، "target.test"))
        اگر asked.نوع رکورد برابر دی‌ان‌اس.نوع آ:
            records.بیفزا(record("target.test"، دی‌ان‌اس.نوع آ، 60، "10.9.9.9"))
        پایان
    وگرنه:
        rcode = 3
    پایان
    برگشت دی‌اوه‌اچ.کدگذاری پاسخ(question.شناسه، asked.نام دامنه، asked.نوع رکورد، rcode، records)
پایان

تابع udp_server():
    s := یو دی پی.پیوند(0)
    udp_port = یو دی پی.درگاه(s)
    همگام سازی.اتمام(ready)
    buf := حافظه.تخصیص(2048 برگردان طبیعی۶۴)
    ناپایا from_host := ""
    ناپایا from_port := 0
    تا درست:
        n := یو دی پی.دریافت بایت(s، buf، 2048، from_host، from_port)
        اگر n بزرگتر 0:
            answer := answer_for(buf، n)
            یو دی پی.ارسال بایت(s، from_host، from_port، answer.داده، answer.طول)
        پایان
    پایان
پایان

تابع start_mock():
    همگام سازی.افزودن(ready، 1 برگردان صحیح۶۴)
    _t := نخ‌ساز(udp_server)
    همگام سازی.انتظار(ready)
پایان

تابع mock_server(name: رشته): دی‌اوه‌اچ.کارگزار:
    ناپایا server := دی‌اوه‌اچ.کارگزار ساده جدید(name، "127.0.0.1")
    server.درگاه = udp_port
    برگشت server
پایان

تابع first(v: وکتور<رشته>): رشته:
    اگر v.طول() برابر 0:
        برگشت "none"
    پایان
    برگشت v.بگیر(0)
پایان

تابع ریشه:
    start_mock()
    ناپایا servers := وکتور {} برگردان وکتور<دی‌اوه‌اچ.کارگزار>
    servers.بیفزا(mock_server("mock"))
    resolver := دی‌اوه‌اچ.حل‌کننده جدید(servers)
    دی‌اوه‌اچ.تعیین مهلت(resolver، 2000)
    دی‌اوه‌اچ.تعیین حدود ماندگاری(resolver، 30، 3600، 15)

    ناپایا a := دی‌اوه‌اچ.حل در زمان(resolver، "a.test"، دی‌ان‌اس.نوع آ، 1000 برگردان صحیح۶۴)
    سرچاپ a.معتبر، a.از حافظه، a.زمان ماندگاری، a.منفی، a.کد نتیجه، a.پیام.پاسخ‌ها.رکوردها.طول()، queries
    ناپایا again := دی‌اوه‌اچ.حل در زمان(resolver، "a.test"، دی‌ان‌اس.نوع آ، 61000 برگردان صحیح۶۴)
    سرچاپ again.از حافظه، again.زمان ماندگاری، queries
    ناپایا later := دی‌اوه‌اچ.حل در زمان(resolver، "a.test"، دی‌ان‌اس.نوع آ، 200000 برگردان صحیح۶۴)
    سرچاپ later.از حافظه، later.زمان ماندگاری، queries
    دی‌اوه‌اچ.آزاد کردن پاسخ نهایی(a)
    دی‌اوه‌اچ.آزاد کردن پاسخ نهایی(again)
    دی‌اوه‌اچ.آزاد کردن پاسخ نهایی(later)

    n1 := دی‌اوه‌اچ.حل در زمان(resolver، "nothing.test"، دی‌ان‌اس.نوع آ، 500000 برگردان صحیح۶۴)
    سرچاپ n1.معتبر، n1.منفی، n1.کد نتیجه، n1.زمان ماندگاری، n1.از حافظه
    n2 := دی‌اوه‌اچ.حل در زمان(resolver، "nothing.test"، دی‌ان‌اس.نوع آ، 505000 برگردان صحیح۶۴)
    سرچاپ n2.از حافظه، n2.منفی، queries
    ناپایا live := دی‌اوه‌اچ.حل(resolver، "a.test"، دی‌ان‌اس.نوع آ)
    سرچاپ live.معتبر، live.از حافظه
    دی‌اوه‌اچ.آزاد کردن پاسخ نهایی(live)

    سرچاپ first(دی‌اوه‌اچ.جستجوی آ(resolver، "a.test"))، دی‌اوه‌اچ.جستجوی آ(resolver، "a.test").طول()
    سرچاپ first(دی‌اوه‌اچ.جستجوی کواداِی(resolver، "v6.test"))، first(دی‌اوه‌اچ.جستجوی تی‌ایکس‌تی(resolver، "txt.test"))
    سرچاپ دی‌اوه‌اچ.جستجوی سی‌نیم(resolver، "alias.test")، first(دی‌اوه‌اچ.جستجوی میزبان(resolver، "alias.test"))، first(دی‌اوه‌اچ.جستجوی میزبان(resolver، "5.6.7.8"))

    stats := دی‌اوه‌اچ.آمار(resolver)
    سرچاپ stats.برخورد حافظه بزرگتر 0، stats.ناکامی حافظه بزرگتر 0، stats.پرسش بالادست بزرگتر 0، stats.شکست‌ها
    سرچاپ دی‌اوه‌اچ.اندازه حافظه(resolver) بزرگتر 0
    دی‌اوه‌اچ.پاک کردن حافظه(resolver)
    سرچاپ دی‌اوه‌اچ.اندازه حافظه(resolver)

    ناپایا dead := وکتور {} برگردان وکتور<دی‌اوه‌اچ.کارگزار>
    dead.بیفزا(دی‌اوه‌اچ.کارگزار جدید("dead"، دی‌اوه‌اچ.نوع دی‌اوه‌اچ پست، "http://127.0.0.1:1/dns-query"))
    broken := دی‌اوه‌اچ.حل‌کننده جدید(dead)
    دی‌اوه‌اچ.تعیین مهلت(broken، 300)
    failed := دی‌اوه‌اچ.حل(broken، "a.test"، دی‌ان‌اس.نوع آ)
    سرچاپ failed.معتبر، failed.خطا.طول() بزرگتر 0، دی‌اوه‌اچ.آمار(broken).شکست‌ها
    سرچاپ first(دی‌اوه‌اچ.جستجوی آ(broken، "a.test"))

    ناپایا helper := وکتور {} برگردان وکتور<دی‌اوه‌اچ.کارگزار>
    helper.بیفزا(mock_server("bootstrap"))
    دی‌اوه‌اچ.تعیین کارگزارهای راه‌انداز(broken، helper)
    سرچاپ "bootstrap set"
پایان
خروجیtrue false 120 false 0 2 1 true 60 1 false 120 2 true true 3 15 false true true 3 true false 10.0.0.1 2 2001:db8:0:0:0:0:0:5 hello world target.test 10.9.9.9 5.6.7.8 true true true 0 true 0 false true 1 none bootstrap set

آمار حل‌کننده ResolverStats

ساختار آمار حل‌کننده
شمارنده‌های یک حل‌کننده. آمار آن‌ها را برمی‌گرداند.
نامانگلیسیگونهتوضیح
برخورد حافظهhitsصحیح۶۴ = 0پرسش‌هایی که از حافظه پاسخ گرفتند.
ناکامی حافظهmissesصحیح۶۴ = 0پرسش‌هایی که در حافظه نبودند.
پرسش بالادستupstreamصحیح۶۴ = 0در مجموع از چند کارگزار پرسیده شد (کارگزار ناموفق و جانشینش دو بار شمرده می‌شوند).
شکست‌هاfailuresصحیح۶۴ = 0پرسش‌هایی که هیچ کارگزاری نتوانست پاسخ دهد.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Resolver.salam

حل‌کننده Resolver

ساختار حل‌کننده
حل‌کننده‌ای با حافظه روی فهرستی از کارگزارها: به ترتیب از آن‌ها می‌پرسد، در شکست به بعدی می‌رود و پاسخ‌ها را به اندازه‌ی TTL‌شان به یاد می‌سپارد. با حل‌کننده جدید ساخته می‌شود؛ استفاده از چند نخ امن است.
نامانگلیسیگونهتوضیح
وضعیتstState*وضعیت درونی: کارگزارها، حافظه، حدها و شمارنده‌ها.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Resolver.salam

پاسخ Response

ساختار پاسخ
پاسخ یک پرسش: پیام خام DNS، پیام رمزگشایی‌شده، مدت زمانش و اینکه کدام کارگزار داد.
نامانگلیسیگونهتوضیح
معتبرokمنطقی = نادرستدرست وقتی پیام DNS معتبری با همان شناسه برگشت. نامی که وجود ندارد هم ok است: rcode پیام را ببینید.
پاسخ خامrawفشرده سازی.بافر بایتپاسخ به شکل بایت‌های سیمی DNS. با آزاد کردن پاسخ آزادش کنید.
پیامmsgدی‌ان‌اس.پیامdns.Message رمزگشایی‌شده: پرسش‌ها، پاسخ‌ها و rcode آن.
زمان رفت‌وبرگشتrtt_msصحیح۶۴ = 0زمان رفت‌وبرگشت به میلی‌ثانیه.
کارگزارserverرشته = ""نام کارگزاری که پاسخ داد.
خطاerrرشته = ""دلیل خوانا وقتی معتبر نادرست است، مثل id mismatch یا خطای اتصال.
net-doh-Query.salam
// زبان: فارسی
واردسازی فشرده سازی
واردسازی حافظه
واردسازی شبکه.دی‌ان‌اس
واردسازی شبکه.دی‌اوه‌اچ
واردسازی شبکه.یو دی پی
واردسازی همگام سازی

ناپایا udp_port := 0
ناپایا queries := 0
ناپایا ready := همگام سازی.گروه انتظار جدید()

تابع record(name: رشته، rtype: صحیح، ttl: صحیح، data: رشته): دی‌ان‌اس.رکورد:
    برگشت دی‌ان‌اس.رکورد { نام دامنه = name، نوع رکورد = rtype، رده = 1، زمان ماندگاری = ttl، داده = data }
پایان

تابع answer_for(p: تهی*، n: صحیح): فشرده سازی.بافر بایت:
    queries++
    question := دی‌ان‌اس.کدگشایی(p، n)
    asked := question.پرسش‌ها.پرسش‌ها.بگیر(0)
    ناپایا records := وکتور {} برگردان وکتور<دی‌ان‌اس.رکورد>
    ناپایا rcode := 0
    اگر asked.نام دامنه برابر "a.test" و asked.نوع رکورد برابر دی‌ان‌اس.نوع آ:
        records.بیفزا(record("a.test"، دی‌ان‌اس.نوع آ، 120، "10.0.0.1"))
        records.بیفزا(record("a.test"، دی‌ان‌اس.نوع آ، 300، "10.0.0.2"))
    وگرنه asked.نام دامنه برابر "v6.test" و asked.نوع رکورد برابر دی‌ان‌اس.نوع کواداِی:
        records.بیفزا(record("v6.test"، دی‌ان‌اس.نوع کواداِی، 300، "2001:db8::5"))
    وگرنه asked.نام دامنه برابر "txt.test" و asked.نوع رکورد برابر دی‌ان‌اس.نوع تی‌ایکس‌تی:
        records.بیفزا(record("txt.test"، دی‌ان‌اس.نوع تی‌ایکس‌تی، 60، "hello world"))
    وگرنه asked.نام دامنه برابر "alias.test":
        records.بیفزا(record("alias.test"، دی‌ان‌اس.نوع سی‌نیم، 60، "target.test"))
        اگر asked.نوع رکورد برابر دی‌ان‌اس.نوع آ:
            records.بیفزا(record("target.test"، دی‌ان‌اس.نوع آ، 60، "10.9.9.9"))
        پایان
    وگرنه:
        rcode = 3
    پایان
    برگشت دی‌اوه‌اچ.کدگذاری پاسخ(question.شناسه، asked.نام دامنه، asked.نوع رکورد، rcode، records)
پایان

تابع udp_server():
    s := یو دی پی.پیوند(0)
    udp_port = یو دی پی.درگاه(s)
    همگام سازی.اتمام(ready)
    buf := حافظه.تخصیص(2048 برگردان طبیعی۶۴)
    ناپایا from_host := ""
    ناپایا from_port := 0
    تا درست:
        n := یو دی پی.دریافت بایت(s، buf، 2048، from_host، from_port)
        اگر n بزرگتر 0:
            answer := answer_for(buf، n)
            یو دی پی.ارسال بایت(s، from_host، from_port، answer.داده، answer.طول)
        پایان
    پایان
پایان

تابع start_mock():
    همگام سازی.افزودن(ready، 1 برگردان صحیح۶۴)
    _t := نخ‌ساز(udp_server)
    همگام سازی.انتظار(ready)
پایان

تابع mock_server(name: رشته): دی‌اوه‌اچ.کارگزار:
    ناپایا server := دی‌اوه‌اچ.کارگزار ساده جدید(name، "127.0.0.1")
    server.درگاه = udp_port
    برگشت server
پایان

تابع ریشه:
    start_mock()
    server := mock_server("mock")
    سرچاپ server.نوع برابر دی‌اوه‌اچ.نوع یو دی پی ساده، server.درگاه برابر udp_port، server.با تی ال اس، server.نشانی‌های راه‌انداز.بگیر(0)

    ناپایا r := دی‌اوه‌اچ.پرسش(server، "a.test"، دی‌ان‌اس.نوع آ، 2000)
    سرچاپ r.معتبر، r.کارگزار، r.پیام.کد نتیجه، r.پیام.پاسخ‌ها.رکوردها.طول()، r.پیام.پاسخ‌ها.رکوردها.بگیر(0).داده
    سرچاپ r.پاسخ خام.طول بزرگتر 12، r.خطا.طول()
    دی‌اوه‌اچ.آزاد کردن پاسخ(r)

    ناپایا direct := دی‌اوه‌اچ.پرسش از نشانی(server، "127.0.0.1"، "v6.test"، دی‌ان‌اس.نوع کواداِی، 2000)
    سرچاپ direct.معتبر، direct.پیام.پاسخ‌ها.رکوردها.بگیر(0).داده
    دی‌اوه‌اچ.آزاد کردن پاسخ(direct)

    ناپایا missing := دی‌اوه‌اچ.پرسش(server، "nothing.test"، دی‌ان‌اس.نوع آ، 2000)
    سرچاپ "missing name:"، missing.معتبر، missing.پیام.کد نتیجه، missing.پیام.پاسخ‌ها.رکوردها.طول()
    دی‌اوه‌اچ.آزاد کردن پاسخ(missing)

    dead := دی‌اوه‌اچ.کارگزار جدید("dead"، دی‌اوه‌اچ.نوع دی‌اوه‌اچ پست، "http://127.0.0.1:1/dns-query")
    failed := دی‌اوه‌اچ.پرسش(dead، "a.test"، دی‌ان‌اس.نوع آ، 500)
    سرچاپ "dead server:"، failed.معتبر، failed.خطا.طول() بزرگتر 0
پایان
خروجیtrue true false 127.0.0.1 true mock 0 2 10.0.0.1 true 0 true 2001:db8:0:0:0:0:0:5 missing name: true 3 0 dead server: false true

کارگزار محلی Stub

ساختار کارگزار محلی
یک کارگزار DNS کوچک روی یک درگاه UDP محلی که از یک حل‌کننده به برنامه‌های دیگر پاسخ می‌دهد. DNS یک برنامه را به آن اشاره بدهید تا جستجوهایش از حل‌کننده‌ی رمزشده و حافظه‌ی شما بگذرد. با راه‌اندازی کارگزار محلی شروع می‌شود.
نامانگلیسیگونهتوضیح
معتبرokمنطقی = نادرستدرست وقتی درگاه بسته شد.
درگاهportصحیح = 0درگاه UDP که روی آن گوش می‌دهد؛ وقتی ۰ خواسته‌اید به کار می‌آید.
میزبانhostرشته = ""نشانی‌ای که stub روی آن گوش می‌دهد.
تی سی پی فعالtcp_okمنطقی = نادرستدرست وقتی سمت TCP stub هم گوش می‌دهد.
وضعیتstStubState*وضعیت درونی.
net-doh-Stub.salam
// زبان: فارسی
واردسازی فشرده سازی
واردسازی حافظه
واردسازی شبکه.دی‌ان‌اس
واردسازی شبکه.دی‌اوه‌اچ
واردسازی شبکه.یو دی پی
واردسازی همگام سازی

ناپایا udp_port := 0
ناپایا queries := 0
ناپایا ready := همگام سازی.گروه انتظار جدید()

تابع record(name: رشته، rtype: صحیح، ttl: صحیح، data: رشته): دی‌ان‌اس.رکورد:
    برگشت دی‌ان‌اس.رکورد { نام دامنه = name، نوع رکورد = rtype، رده = 1، زمان ماندگاری = ttl، داده = data }
پایان

تابع answer_for(p: تهی*، n: صحیح): فشرده سازی.بافر بایت:
    queries++
    question := دی‌ان‌اس.کدگشایی(p، n)
    asked := question.پرسش‌ها.پرسش‌ها.بگیر(0)
    ناپایا records := وکتور {} برگردان وکتور<دی‌ان‌اس.رکورد>
    ناپایا rcode := 0
    اگر asked.نام دامنه برابر "a.test" و asked.نوع رکورد برابر دی‌ان‌اس.نوع آ:
        records.بیفزا(record("a.test"، دی‌ان‌اس.نوع آ، 120، "10.0.0.1"))
        records.بیفزا(record("a.test"، دی‌ان‌اس.نوع آ، 300، "10.0.0.2"))
    وگرنه asked.نام دامنه برابر "v6.test" و asked.نوع رکورد برابر دی‌ان‌اس.نوع کواداِی:
        records.بیفزا(record("v6.test"، دی‌ان‌اس.نوع کواداِی، 300، "2001:db8::5"))
    وگرنه asked.نام دامنه برابر "txt.test" و asked.نوع رکورد برابر دی‌ان‌اس.نوع تی‌ایکس‌تی:
        records.بیفزا(record("txt.test"، دی‌ان‌اس.نوع تی‌ایکس‌تی، 60، "hello world"))
    وگرنه asked.نام دامنه برابر "alias.test":
        records.بیفزا(record("alias.test"، دی‌ان‌اس.نوع سی‌نیم، 60، "target.test"))
        اگر asked.نوع رکورد برابر دی‌ان‌اس.نوع آ:
            records.بیفزا(record("target.test"، دی‌ان‌اس.نوع آ، 60، "10.9.9.9"))
        پایان
    وگرنه:
        rcode = 3
    پایان
    برگشت دی‌اوه‌اچ.کدگذاری پاسخ(question.شناسه، asked.نام دامنه، asked.نوع رکورد، rcode، records)
پایان

تابع udp_server():
    s := یو دی پی.پیوند(0)
    udp_port = یو دی پی.درگاه(s)
    همگام سازی.اتمام(ready)
    buf := حافظه.تخصیص(2048 برگردان طبیعی۶۴)
    ناپایا from_host := ""
    ناپایا from_port := 0
    تا درست:
        n := یو دی پی.دریافت بایت(s، buf، 2048، from_host، from_port)
        اگر n بزرگتر 0:
            answer := answer_for(buf، n)
            یو دی پی.ارسال بایت(s، from_host، from_port، answer.داده، answer.طول)
        پایان
    پایان
پایان

تابع start_mock():
    همگام سازی.افزودن(ready، 1 برگردان صحیح۶۴)
    _t := نخ‌ساز(udp_server)
    همگام سازی.انتظار(ready)
پایان

تابع mock_server(name: رشته): دی‌اوه‌اچ.کارگزار:
    ناپایا server := دی‌اوه‌اچ.کارگزار ساده جدید(name، "127.0.0.1")
    server.درگاه = udp_port
    برگشت server
پایان

تابع ریشه:
    start_mock()
    ناپایا servers := وکتور {} برگردان وکتور<دی‌اوه‌اچ.کارگزار>
    servers.بیفزا(mock_server("mock"))
    resolver := دی‌اوه‌اچ.حل‌کننده جدید(servers)
    stub := دی‌اوه‌اچ.راه‌اندازی کارگزار محلی(resolver، "127.0.0.1"، 0)
    سرچاپ "stub up:"، stub.معتبر، stub.درگاه بزرگتر 0

    sock := یو دی پی.باز کردن()
    یو دی پی.تنظیم زمان انتظار(sock، 3000)
    buf := حافظه.تخصیص(2048 برگردان طبیعی۶۴)
    ناپایا from_host := ""
    ناپایا from_port := 0
    هر name در ["a.test"، "a.test"، "nothing.test"]:
        ناپایا asked := فشرده سازی.بافر بایت جدید()
        فشرده سازی.افزودن بایت(asked، 0x12)
        فشرده سازی.افزودن بایت(asked، 0x34)
        فشرده سازی.افزودن بایت(asked، 0x01)
        فشرده سازی.افزودن بایت(asked، 0x00)
        فشرده سازی.افزودن بایت(asked، 0)
        فشرده سازی.افزودن بایت(asked، 1)
        تکرار 6:
            فشرده سازی.افزودن بایت(asked، 0)
        پایان
        هر label در name.بشکاف("."):
            فشرده سازی.افزودن بایت(asked، label.طول())
            فشرده سازی.افزودن بایت‌ها(asked، label برگردان تهی*، label.طول())
        پایان
        فشرده سازی.افزودن بایت(asked، 0)
        فشرده سازی.افزودن بایت(asked، 0)
        فشرده سازی.افزودن بایت(asked، 1)
        فشرده سازی.افزودن بایت(asked، 0)
        فشرده سازی.افزودن بایت(asked، 1)
        یو دی پی.ارسال بایت(sock، "127.0.0.1"، stub.درگاه، asked.داده، asked.طول)
        n := یو دی پی.دریافت بایت(sock، buf، 2048، from_host، from_port)
        reply := دی‌ان‌اس.کدگشایی(buf، n)
        سرچاپ name، reply.شناسه برابر 4660، reply.کد نتیجه، reply.پاسخ‌ها.رکوردها.طول()، queries
    پایان
    سرچاپ "served:"، دی‌اوه‌اچ.شمار پاسخ‌های کارگزار محلی(stub)
    دی‌اوه‌اچ.توقف کارگزار محلی(stub)
    یو دی پی.بستن(sock)
پایان
خروجیstub up: true true a.test true 0 2 1 a.test true 0 2 1 nothing.test true 3 0 2 served: 3

کارگزار Server

ساختار کارگزار
یک کارگزار DNS و شیوه‌ی حرف زدن با آن: پروتکل، جایش و کدام نشانی‌ها نخست امتحان شوند. تابع‌های پیش‌تنظیم و کارگزار جدید، کارگزار دی‌اوه‌تی جدید و کارگزار ساده جدید آن‌ها را می‌سازند.
نامانگلیسیگونهتوضیح
نامnameرشته = ""نام کوتاه برای گزارش‌ها و کارگزار.
نوعkindصحیح = 0نوع دی‌اوه‌اچ پست، نوع دی‌اوه‌اچ گت، نوع دی‌اوه‌تی یا نوع یو دی پی ساده.
نشانیurlرشته = ""نشانی یک نقطه‌ی DoH، مثل https://dns.google/dns-query.
میزبانhostرشته = ""نام میزبان (برای نام TLS و سرآیند Host) یا IP.
درگاهportصحیح = 0درگاه: ۴۴۳ برای DoH، ۸۵۳ برای DoT، ۵۳ برای DNS ساده.
مسیرpathرشته = ""مسیر درخواست یک نقطه‌ی DoH.
با تی ال اسuse_tlsمنطقی = درستدرست وقتی کارگزار TLS به کار می‌برد. برای DoH روی https و برای DoT درست است.
نشانی‌های راه‌اندازaddrsوکتور<رشته>نشانی‌های IP برای اتصال، تا نام خود کارگزار لازم نباشد از پیش جستجو شود. همین است که وقتی خود DNS مسدود است یک حل‌کننده‌ی رمزشده را کار می‌اندازد.
ناامنinsecureمنطقی = نادرستدرست یعنی بررسی گواهی نادیده گرفته شود. فقط برای آزمون.
net-doh-Servers.salam
// زبان: فارسی
واردسازی شبکه.دی‌اوه‌اچ

تابع ریشه:
    cloudflare := دی‌اوه‌اچ.کلودفلر()
    سرچاپ cloudflare.نام، cloudflare.نوع برابر دی‌اوه‌اچ.نوع دی‌اوه‌اچ پست، cloudflare.نشانی، cloudflare.میزبان، cloudflare.درگاه، cloudflare.مسیر، cloudflare.با تی ال اس
    سرچاپ cloudflare.نشانی‌های راه‌انداز.بگیر(0)، cloudflare.نشانی‌های راه‌انداز.بگیر(1)
    سرچاپ دی‌اوه‌اچ.گوگل().میزبان، دی‌اوه‌اچ.گوگل().نشانی‌های راه‌انداز.بگیر(0)، دی‌اوه‌اچ.کواد نه().میزبان، دی‌اوه‌اچ.کواد نه().نشانی‌های راه‌انداز.بگیر(0)
    dot := دی‌اوه‌اچ.کلودفلر دی‌اوه‌تی()
    سرچاپ dot.نوع برابر دی‌اوه‌اچ.نوع دی‌اوه‌تی، dot.میزبان، dot.درگاه، dot.نشانی‌های راه‌انداز.بگیر(0)
    سرچاپ دی‌اوه‌اچ.گوگل دی‌اوه‌تی().نشانی‌های راه‌انداز.بگیر(0)، دی‌اوه‌اچ.کواد نه دی‌اوه‌تی().میزبان

    custom := دی‌اوه‌اچ.کارگزار جدید("mine"، دی‌اوه‌اچ.نوع دی‌اوه‌اچ گت، "https://dns.example.net/resolve")
    سرچاپ custom.نوع برابر دی‌اوه‌اچ.نوع دی‌اوه‌اچ گت، custom.میزبان، custom.مسیر، custom.نشانی‌های راه‌انداز.طول()
    pinned := دی‌اوه‌اچ.با نشانی راه‌انداز(custom، "203.0.113.53")
    سرچاپ pinned.نشانی‌های راه‌انداز.طول()، custom.نشانی‌های راه‌انداز.طول()، pinned.نشانی‌های راه‌انداز.بگیر(0)

    mine := دی‌اوه‌اچ.کارگزار دی‌اوه‌تی جدید("dot"، "dns.example.net"، "203.0.113.54")
    plain := دی‌اوه‌اچ.کارگزار ساده جدید("plain"، "203.0.113.55")
    سرچاپ mine.درگاه، mine.با تی ال اس، plain.درگاه، plain.نوع برابر دی‌اوه‌اچ.نوع یو دی پی ساده، plain.با تی ال اس
    سرچاپ دی‌اوه‌اچ.نوع دی‌اوه‌اچ پست، دی‌اوه‌اچ.نوع دی‌اوه‌اچ گت، دی‌اوه‌اچ.نوع دی‌اوه‌تی، دی‌اوه‌اچ.نوع یو دی پی ساده

    ناپایا servers := دی‌اوه‌اچ.کارگزارهای پیش‌فرض()
    سرچاپ servers.طول()، servers.بگیر(0).نام، servers.بگیر(2).نام
    iran := دی‌اوه‌اچ.کارگزارهای ساده ایران()
    سرچاپ iran.طول()، iran.بگیر(0).نام، iran.بگیر(0).درگاه، iran.بگیر(0).نشانی‌های راه‌انداز.بگیر(0)
    سرچاپ دی‌اوه‌اچ.شکن().طول()، دی‌اوه‌اچ.الکترو().بگیر(0).نام، دی‌اوه‌اچ.رادار().بگیر(1).نام، دی‌اوه‌اچ.بگزر().بگیر(0).نشانی‌های راه‌انداز.بگیر(0)
    دی‌اوه‌اچ.آزاد کردن کارگزارها(servers)
پایان
خروجیcloudflare true https://cloudflare-dns.com/dns-query cloudflare-dns.com 443 /dns-query true 1.1.1.1 1.0.0.1 dns.google 8.8.8.8 dns.quad9.net 9.9.9.9 true one.one.one.one 853 1.1.1.1 8.8.8.8 dns.quad9.net true dns.example.net /resolve 0 1 0 203.0.113.53 853 true 53 true false 0 1 2 3 3 cloudflare quad9 6 shecan 53 178.22.122.100 2 electro radar2 185.55.226.26

نشانی وب Url

ساختار نشانی وب
یک نشانی DoH تجزیه‌شده: طرح (به شکل با تی ال اس)، میزبان، درگاه و مسیر.
نامانگلیسیگونهتوضیح
معتبرokمنطقی = نادرستدرست وقتی نشانی معتبر بود.
با تی ال اسuse_tlsمنطقی = درستبرای https درست، برای http نادرست.
میزبانhostرشته = ""میزبان.
درگاهportصحیح = 0درگاه، یا ۴۴۳ یا ۸۰ اگر نشانی نداشته باشد.
مسیرpathرشته = ""مسیر با پرسمان، دست‌کم /.
net-doh-Parse.salam
// زبان: فارسی
واردسازی فشرده سازی
واردسازی شبکه.دی‌ان‌اس
واردسازی شبکه.دی‌اوه‌اچ

تابع ریشه:
    سرچاپ دی‌اوه‌اچ.نشانی آی‌پی است("1.2.3.4")، دی‌اوه‌اچ.نشانی آی‌پی است("2001:db8::1")، دی‌اوه‌اچ.نشانی آی‌پی است("dns.google")، دی‌اوه‌اچ.نشانی آی‌پی است("1.2.3")
    url := دی‌اوه‌اچ.تجزیه نشانی وب("https://dns.example.net/dns-query")
    سرچاپ url.معتبر، url.با تی ال اس، url.میزبان، url.درگاه، url.مسیر
    plain := دی‌اوه‌اچ.تجزیه نشانی وب("http://127.0.0.1:8053")
    سرچاپ plain.معتبر، plain.با تی ال اس، plain.درگاه، plain.مسیر
    سرچاپ دی‌اوه‌اچ.تجزیه نشانی وب("ftp://x").معتبر

    ناپایا v4 := فشرده سازی.بافر بایت جدید()
    سرچاپ دی‌اوه‌اچ.تجزیه آی‌پی۴("10.0.0.7"، v4)، v4.طول
    ناپایا v6 := فشرده سازی.بافر بایت جدید()
    سرچاپ دی‌اوه‌اچ.تجزیه آی‌پی۶("2001:db8::7"، v6)، v6.طول
    سرچاپ دی‌اوه‌اچ.تجزیه آی‌پی۴("10.0.0"، فشرده سازی.بافر بایت جدید())

    ناپایا records := وکتور {} برگردان وکتور<دی‌ان‌اس.رکورد>
    records.بیفزا(دی‌ان‌اس.رکورد { نام دامنه = "example.test"، نوع رکورد = دی‌ان‌اس.نوع آ، رده = 1، زمان ماندگاری = 300، داده = "192.0.2.7" })
    wire := دی‌اوه‌اچ.کدگذاری پاسخ(4242، "example.test"، دی‌ان‌اس.نوع آ، 0، records)
    message := دی‌ان‌اس.کدگشایی(wire.داده، wire.طول)
    سرچاپ message.شناسه، message.نشانه پاسخ، message.کد نتیجه، message.پرسش‌ها.پرسش‌ها.طول()، message.پاسخ‌ها.رکوردها.طول()
    answer := message.پاسخ‌ها.رکوردها.بگیر(0)
    سرچاپ answer.نام دامنه، answer.زمان ماندگاری، answer.داده
    nx := دی‌اوه‌اچ.کدگذاری پاسخ(7، "nothing.test"، دی‌ان‌اس.نوع آ، 3، وکتور {} برگردان وکتور<دی‌ان‌اس.رکورد>)
    سرچاپ دی‌ان‌اس.کدگشایی(nx.داده، nx.طول).کد نتیجه
پایان
خروجیtrue true false false true true dns.example.net 443 /dns-query true false 8053 / false true 4 true 16 false 4242 true 0 1 1 example.test 300 192.0.2.7 3

پایاها و متغیرها

نوع‌های کارگزار Kind…

مقدارهای نوع.
نامانگلیسیمقدار
نوع دی‌اوه‌اچ پستKindDoH0
نوع دی‌اوه‌اچ گتKindDoHGet1
نوع دی‌اوه‌تیKindDoT2
نوع یو دی پی سادهKindUDP3
net-doh-Http.salam
// زبان: فارسی
واردسازی فشرده سازی
واردسازی حافظه
واردسازی شبکه.دی‌ان‌اس
واردسازی شبکه.دی‌اوه‌اچ
واردسازی شبکه.تی سی پی
واردسازی رشته
واردسازی همگام سازی

ناپایا http_port := 0
ناپایا methods := ""
ناپایا ready := همگام سازی.گروه انتظار جدید()

تابع find_text(b: فشرده سازی.بافر بایت، pattern: رشته): صحیح:
    n := pattern.طول()
    ناپایا i := 0
    تا i + n کوچکتربرابر b.طول:
        ناپایا same := درست
        تکرار n در j:
            اگر فشرده سازی.دریافت بایت(b، i + j) نابرابر (pattern برگردان طبیعی۸*)[j] برگردان صحیح:
                same = نادرست
                بشکن
            پایان
        پایان
        اگر same:
            برگشت i
        پایان
        i++
    پایان
    برگشت 0 - 1
پایان

تابع text_at(b: فشرده سازی.بافر بایت، off: صحیح، n: صحیح): رشته:
    buf := حافظه.تخصیص((n + 1) برگردان طبیعی۶۴)
    حافظه.کپی(buf، ((b.داده برگردان صحیح۶۴) + (off برگردان صحیح۶۴)) برگردان تهی*، n برگردان طبیعی۶۴)
    (buf برگردان طبیعی۸*)[n] = 0 برگردان طبیعی۸
    برگشت buf برگردان رشته
پایان

تابع from_base64url(s: رشته): فشرده سازی.بافر بایت:
    alphabet := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
    ناپایا out := فشرده سازی.بافر بایت جدید()
    ناپایا acc := 0
    ناپایا bits := 0
    تکرار s.طول() در i:
        v := alphabet.بیاب(s.زیررشته(i، 1))
        اگر v کوچکتر 0:
            بشکن
        پایان
        acc = (acc << 6) | v
        bits += 6
        اگر bits بزرگتربرابر 8:
            bits -= 8
            فشرده سازی.افزودن بایت(out، (acc >> bits) & 255)
            acc = acc & ((1 << bits) - 1)
        پایان
    پایان
    برگشت out
پایان

تابع serve_one(c: تی سی پی.اتصال شبکه):
    ناپایا raw := فشرده سازی.بافر بایت جدید()
    buf := حافظه.تخصیص(4096 برگردان طبیعی۶۴)
    ناپایا head_end := 0 - 1
    ناپایا need := 0
    تا درست:
        n := تی سی پی.خواندن بایت(c، buf، 4096)
        اگر n کوچکتربرابر 0:
            بشکن
        پایان
        فشرده سازی.افزودن بایت‌ها(raw، buf، n)
        head_end = find_text(raw، "\r\n\r\n")
        اگر head_end بزرگتربرابر 0:
            head := رشته.کوچک(text_at(raw، 0، head_end))
            at := head.بیاب("content-length:")
            اگر at بزرگتربرابر 0:
                rest := head.زیررشته(at + 15، head.طول() - at - 15)
                ناپایا line_end := rest.بیاب("\r\n")
                اگر line_end کوچکتر 0:
                    line_end = rest.طول()
                پایان
                need = رشته.پیرایش(rest.زیررشته(0، line_end)).به صحیح()
            پایان
            اگر raw.طول بزرگتربرابر head_end + 4 + need:
                بشکن
            پایان
        پایان
    پایان
    ناپایا wire := فشرده سازی.بافر بایت جدید()
    اگر text_at(raw، 0، 4) برابر "POST":
        methods += "POST "
        فشرده سازی.افزودن بایت‌ها(wire، ((raw.داده برگردان صحیح۶۴) + (head_end برگردان صحیح۶۴) + 4) برگردان تهی*، need)
    وگرنه:
        methods += "GET "
        line := text_at(raw، 0، find_text(raw، "\r\n"))
        rest := line.زیررشته(line.بیاب("dns=") + 4، line.طول())
        wire = from_base64url(rest.زیررشته(0، rest.بیاب(" ")))
    پایان
    question := دی‌ان‌اس.کدگشایی(wire.داده، wire.طول)
    asked := question.پرسش‌ها.پرسش‌ها.بگیر(0)
    ناپایا records := وکتور {} برگردان وکتور<دی‌ان‌اس.رکورد>
    records.بیفزا(دی‌ان‌اس.رکورد { نام دامنه = asked.نام دامنه، نوع رکورد = دی‌ان‌اس.نوع آ، رده = 1، زمان ماندگاری = 300، داده = "192.0.2.80" })
    answer := دی‌اوه‌اچ.کدگذاری پاسخ(question.شناسه، asked.نام دامنه، asked.نوع رکورد، 0، records)
    head := "HTTP/1.1 200 OK\r\nContent-Type: application/dns-message\r\nConnection: close\r\nContent-Length: " + answer.طول + "\r\n\r\n"
    تی سی پی.نوشتن(c، head)
    تی سی پی.نوشتن بایت(c، answer.داده، answer.طول)
    تی سی پی.بستن(c)
پایان

تابع http_server():
    srv := تی سی پی.پیوند(0)
    http_port = تی سی پی.درگاه(srv)
    همگام سازی.اتمام(ready)
    تا درست:
        serve_one(تی سی پی.پذیرش(srv))
    پایان
پایان

تابع ریشه:
    همگام سازی.افزودن(ready، 1 برگردان صحیح۶۴)
    _t := نخ‌ساز(http_server)
    همگام سازی.انتظار(ready)
    base := "http://127.0.0.1:" + http_port + "/dns-query"

    post := دی‌اوه‌اچ.کارگزار جدید("post"، دی‌اوه‌اچ.نوع دی‌اوه‌اچ پست، base)
    سرچاپ post.با تی ال اس، post.درگاه برابر http_port، post.مسیر
    r := دی‌اوه‌اچ.پرسش(post، "web.test"، دی‌ان‌اس.نوع آ، 2000)
    سرچاپ r.معتبر، r.پیام.پاسخ‌ها.رکوردها.بگیر(0).داده

    get := دی‌اوه‌اچ.کارگزار جدید("get"، دی‌اوه‌اچ.نوع دی‌اوه‌اچ گت، base)
    g := دی‌اوه‌اچ.پرسش(get، "web.test"، دی‌ان‌اس.نوع آ، 2000)
    سرچاپ g.معتبر، g.پیام.پاسخ‌ها.رکوردها.بگیر(0).داده
    سرچاپ methods
پایان
خروجیfalse true /dns-query true 192.0.2.80 true 192.0.2.80 POST GET

تابع‌ها

حل‌کننده جدید NewResolver

تابع حل‌کننده جدید(servers: وکتور<کارگزار>): حل‌کننده
حل‌کننده‌ای می‌سازد که از این کارگزارها به ترتیب می‌پرسد. پیش‌فرض‌ها: کمینه‌ی TTL ده ثانیه، بیشینه ۸۶۴۰۰، سی ثانیه برای شکست‌ها، مهلت ۴۰۰۰ میلی‌ثانیه و ۲۰۴۸ ورودی حافظه.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Resolver.salam

تعیین کارگزارهای راه‌انداز SetBootstrap

تابع تعیین کارگزارهای راه‌انداز(r: حل‌کننده، servers: وکتور<کارگزار>)
کارگزارهایی را تعیین می‌کند که برای پیدا کردن نشانی یک کارگزار DoH یا DoT به کار می‌روند که نام میزبان دارد ولی نشانی‌های راه‌انداز ندارد. باید با IP در دسترس باشند، مثلا کارگزارهای ساده.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Resolver.salam

تعیین حدود ماندگاری SetTTLLimits

تابع تعیین حدود ماندگاری(r: حل‌کننده، min_ttl: صحیح، max_ttl: صحیح، neg_ttl: صحیح)
کمترین و بیشترین زمانی را که یک پاسخ نگه داشته می‌شود و مدتی را که یک شکست («چنین نامی نیست») نگه داشته می‌شود، به ثانیه تعیین می‌کند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Resolver.salam

تعیین مهلت SetTimeout

تابع تعیین مهلت(r: حل‌کننده، timeout_ms: صحیح)
تعیین می‌کند هر پرسش از یک کارگزار چند میلی‌ثانیه می‌تواند طول بکشد.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Resolver.salam

آمار Stats

تابع آمار(r: حل‌کننده): آمار حل‌کننده
شمارنده‌های یک حل‌کننده را برمی‌گرداند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Resolver.salam

اندازه حافظه CacheSize

تابع اندازه حافظه(r: حل‌کننده): صحیح
شمار ورودی‌های حافظه.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Resolver.salam

پاک کردن حافظه ClearCache

تابع پاک کردن حافظه(r: حل‌کننده)
همه‌ی پاسخ‌های نگه‌داری‌شده را دور می‌ریزد.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Resolver.salam

حل در زمان ResolveAt

تابع حل در زمان(r: حل‌کننده، name: رشته، qtype: صحیح، now_ms: صحیح۶۴): پاسخ نهایی
مثل حل ولی با ساعت داده‌شده به میلی‌ثانیه، تا حافظه را بتوان بی‌انتظار آزمود.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Resolver.salam

حل Resolve

تابع حل(r: حل‌کننده، name: رشته، qtype: صحیح): پاسخ نهایی
پرسشی را از حافظه پاسخ می‌دهد، یا از کارگزارها به ترتیب می‌پرسد و نتیجه را نگه می‌دارد. کارگزاری که شکست بخورد، مهلتش تمام شود یا SERVFAIL یا REFUSED بدهد برای بعدی کنار گذاشته می‌شود؛ پاسخ «چنین نامی نیست» نهایی است و مدت کوتاهی نگه داشته می‌شود.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Resolver.salam

آزاد کردن پاسخ نهایی FreeAnswer

تابع آزاد کردن پاسخ نهایی(a &: پاسخ نهایی)
بایت‌های خام یک پاسخ را آزاد می‌کند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Resolver.salam

جستجوی آ LookupA

تابع جستجوی آ(r: حل‌کننده، name: رشته): وکتور<رشته>
نشانی‌های IPv4 یک نام را به شکل متن برمی‌گرداند. اگر نباشد خالی.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Resolver.salam

جستجوی کواداِی LookupAAAA

تابع جستجوی کواداِی(r: حل‌کننده، name: رشته): وکتور<رشته>
نشانی‌های IPv6 یک نام را به شکل متن برمی‌گرداند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Resolver.salam

جستجوی تی‌ایکس‌تی LookupTXT

تابع جستجوی تی‌ایکس‌تی(r: حل‌کننده، name: رشته): وکتور<رشته>
رکوردهای TXT یک نام را برمی‌گرداند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Resolver.salam

جستجوی سی‌نیم LookupCNAME

تابع جستجوی سی‌نیم(r: حل‌کننده، name: رشته): رشته
نام اصلی‌ای را که یک نام به آن اشاره می‌کند برمی‌گرداند، یا متن خالی.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Resolver.salam

جستجوی میزبان LookupHost

تابع جستجوی میزبان(r: حل‌کننده، name: رشته): وکتور<رشته>
نشانی‌های یک نام را برمی‌گرداند، نخست IPv4 و سپس IPv6. نامی که خودش IP است بی‌آنکه از کسی بپرسد همان برمی‌گردد.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Resolver.salam

پرسش از نشانی QueryAddr

تابع پرسش از نشانی(srv: کارگزار، addr: رشته، name: رشته، qtype: صحیح، timeout_ms: صحیح): پاسخ
یک پرسش را به یک نشانی از یک کارگزار می‌فرستد و تا مهلت منتظر می‌ماند. وقتی از پیش می‌دانید از کدام IP بپرسید به کار ببرید.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Query.salam

پرسش Query

تابع پرسش(srv: کارگزار، name: رشته، qtype: صحیح، timeout_ms: صحیح): پاسخ
یک پرسش را به یک کارگزار می‌فرستد و هر یک از نشانی‌های راه‌انداز آن را به نوبت امتحان می‌کند، یا اگر ندارد نام میزبانش را حل می‌کند. پرسش از نشانی یک نشانی را انجام می‌دهد.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Query.salam

آزاد کردن پاسخ FreeResponse

تابع آزاد کردن پاسخ(r &: پاسخ)
بایت‌های خام یک پاسخ را آزاد می‌کند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Query.salam

اتصال‌های بازاستفاده‌شده ReusedConnections

تابع اتصال‌های بازاستفاده‌شده(): صحیح۶۴
شمار پرس‌وجوهای DoH تا اینجا که از اتصال نگه‌داشته‌شده‌ی پرس‌وجوی پیشین استفاده کردند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Http.salam

بستن اتصال‌های بی‌کار CloseIdleConnections

تابع بستن اتصال‌های بی‌کار()
اتصال‌های نگه‌داشته‌ی بی‌کار DoH را می‌بندد.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Http.salam

راه‌اندازی کارگزار محلی StartStub

تابع راه‌اندازی کارگزار محلی(r: حل‌کننده، host: رشته، port: صحیح): کارگزار محلی
کارگزار DNS محلی را روی یک میزبان و درگاه (۰ یکی آزاد برمی‌گزیند) با پاسخ روی UDP و TCP روی نخ‌های پس‌زمینه راه می‌اندازد. میزبان خالی یعنی 127.0.0.1. معتبر و برای سمت TCP tcp_ok را بررسی کنید.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Stub.salam

شمار پاسخ‌های کارگزار محلی StubServed

تابع شمار پاسخ‌های کارگزار محلی(s: کارگزار محلی): صحیح۶۴
کارگزار محلی به چند پرسش پاسخ داده است.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Stub.salam

توقف کارگزار محلی StopStub

تابع توقف کارگزار محلی(s: کارگزار محلی)
کارگزار DNS محلی را می‌ایستاند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Stub.salam

تجزیه آی‌پی۴ ParseIPv4

تابع تجزیه آی‌پی۴(text: رشته، out &: فشرده سازی.بافر بایت): منطقی
متن IPv4 را به چهار بایت تجزیه می‌کند که به یک بافر اضافه می‌شود. اگر نشانی نبود نادرست.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Parse.salam

تجزیه آی‌پی۶ ParseIPv6

تابع تجزیه آی‌پی۶(text: رشته، out &: فشرده سازی.بافر بایت): منطقی
متن IPv6 را به شانزده بایت تجزیه می‌کند که به یک بافر اضافه می‌شود. اگر نشانی نبود نادرست.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Parse.salam

نشانی آی‌پی است IsIP

تابع نشانی آی‌پی است(host: رشته): منطقی
درست وقتی متن یک نشانی IPv4 یا IPv6 است و نه یک نام.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Parse.salam

تجزیه نشانی وب ParseURL

تابع تجزیه نشانی وب(raw: رشته): نشانی وب
یک نشانی http:// یا https:// را تجزیه می‌کند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Parse.salam

کارگزار جدید NewServer

تابع کارگزار جدید(name: رشته، kind: صحیح، url: رشته): کارگزار
از یک نام، یک نوع و یک نشانی کارگزار می‌سازد. برای دو نوع DoH میزبان، درگاه، مسیر و پرچم TLS از نشانی گرفته می‌شود. نشانی‌های راه‌انداز را اضافه کنید یا با نشانی راه‌انداز را به کار ببرید تا نامش نیازی به حل شدن نداشته باشد.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Servers.salam

کارگزار دی‌اوه‌تی جدید NewDoT

تابع کارگزار دی‌اوه‌تی جدید(name: رشته، host: رشته، addr: رشته): کارگزار
یک کارگزار DNS روی TLS از یک نام، نام میزبان TLS و یک نشانی IP می‌سازد، روی درگاه ۸۵۳.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Servers.salam

کارگزار ساده جدید NewPlain

تابع کارگزار ساده جدید(name: رشته، addr: رشته): کارگزار
یک کارگزار DNS ساده‌ی UDP روی درگاه ۵۳ از یک نام و یک نشانی IP می‌سازد. برای درگاه دیگر درگاه را تغییر دهید.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Servers.salam

با نشانی راه‌انداز WithBootstrap

تابع با نشانی راه‌انداز(s: کارگزار، addr: رشته): کارگزار
نسخه‌ای از یک کارگزار را با یک نشانی IP بیشتر برای امتحان برمی‌گرداند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Servers.salam

با نشانی آی‌پی۶ WithIPv6

تابع با نشانی آی‌پی۶(s: کارگزار): کارگزار
کارگزار را با نشانی‌های IPv6 شناخته‌شده‌ی کلودفلر، گوگل یا Quad9 در فهرست راه‌انداز برمی‌گرداند، بر پایه‌ی نام میزبانش. کارگزارهای دیگر بی‌تغییر برمی‌گردند.
net-doh-IPv6.salam
// زبان: فارسی
واردسازی شبکه.دی‌اوه‌اچ

تابع ریشه:
    v6 := دی‌اوه‌اچ.کلودفلر آی‌پی۶()
    سرچاپ v6.نشانی‌های راه‌انداز.بگیر(0)، دی‌اوه‌اچ.گوگل آی‌پی۶().نشانی‌های راه‌انداز.بگیر(0)، دی‌اوه‌اچ.کواد نه آی‌پی۶().نشانی‌های راه‌انداز.بگیر(0)
    both := دی‌اوه‌اچ.با نشانی آی‌پی۶(دی‌اوه‌اچ.کلودفلر())
    سرچاپ both.نشانی‌های راه‌انداز.طول()
پایان

کلودفلر آی‌پی۶ Cloudflare6

تابع کلودفلر آی‌پی۶(): کارگزار
کارگزار کلودفلر روی DoH که فقط با نشانی‌های IPv6 اش در دسترس است.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-IPv6.salam

گوگل آی‌پی۶ Google6

تابع گوگل آی‌پی۶(): کارگزار
کارگزار گوگل روی DoH که فقط با نشانی‌های IPv6 اش در دسترس است.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-IPv6.salam

کواد نه آی‌پی۶ Quad96

تابع کواد نه آی‌پی۶(): کارگزار
کارگزار Quad9 روی DoH که فقط با نشانی‌های IPv6 اش در دسترس است.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-IPv6.salam

کلودفلر Cloudflare

تابع کلودفلر(): کارگزار
حل‌کننده‌ی Cloudflare روی DoH (cloudflare-dns.com)، با نشانی‌های 1.1.1.1 و 1.0.0.1.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Servers.salam

گوگل Google

تابع گوگل(): کارگزار
حل‌کننده‌ی Google روی DoH (dns.google)، با 8.8.8.8 و 8.8.4.4.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Servers.salam

کواد نه Quad9

تابع کواد نه(): کارگزار
حل‌کننده‌ی Quad9 روی DoH (dns.quad9.net)، با 9.9.9.9 و 149.112.112.112.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Servers.salam

کلودفلر دی‌اوه‌تی CloudflareDoT

تابع کلودفلر دی‌اوه‌تی(): کارگزار
حل‌کننده‌ی Cloudflare روی DNS روی TLS، در 1.1.1.1.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Servers.salam

گوگل دی‌اوه‌تی GoogleDoT

تابع گوگل دی‌اوه‌تی(): کارگزار
حل‌کننده‌ی Google روی DNS روی TLS، در 8.8.8.8.
net-doh-Encrypted.salam
// زبان: فارسی
واردسازی شبکه.دی‌اوه‌اچ

تابع ریشه:
    ناپایا servers := وکتور {} برگردان وکتور<دی‌اوه‌اچ.کارگزار>
    servers.بیفزا(دی‌اوه‌اچ.کلودفلر())
    servers.بیفزا(دی‌اوه‌اچ.گوگل دی‌اوه‌تی())
    servers.بیفزا(دی‌اوه‌اچ.کواد نه())
    resolver := دی‌اوه‌اچ.حل‌کننده جدید(servers)
    دی‌اوه‌اچ.تعیین مهلت(resolver، 3000)

    answer := دی‌اوه‌اچ.حل(resolver، "example.com"، 1)
    سرچاپ answer.معتبر، answer.از حافظه، answer.کارگزار، answer.زمان ماندگاری
    هر ip در دی‌اوه‌اچ.جستجوی میزبان(resolver، "example.com"):
        سرچاپ ip
    پایان

    stub := دی‌اوه‌اچ.راه‌اندازی کارگزار محلی(resolver، "127.0.0.1"، 5353)
    سرچاپ "local resolver on port"، stub.درگاه
    دی‌اوه‌اچ.توقف کارگزار محلی(stub)
پایان

کواد نه دی‌اوه‌تی Quad9DoT

تابع کواد نه دی‌اوه‌تی(): کارگزار
حل‌کننده‌ی Quad9 روی DNS روی TLS، در 9.9.9.9.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Servers.salam

کارگزارهای پیش‌فرض DefaultServers

تابع کارگزارهای پیش‌فرض(): وکتور<کارگزار>
Cloudflare، Google و Quad9 روی DoH، به همین ترتیب: فهرست معقولی برای یک حل‌کننده.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Servers.salam

شکن Shecan

تابع شکن(): وکتور<کارگزار>
دو کارگزار ساده‌ی UDP سرویس DNS شکن که در ایران به کار می‌رود. رمزشده نیستند. نشانی‌ها با سایت رسمی تأیید نشده‌اند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Servers.salam

چهارصدوسه Server403

تابع چهارصدوسه(): وکتور<کارگزار>
دو کارگزار ساده‌ی UDP سرویس DNS ۴۰۳. نشانی‌هایشان خصوصی است و فقط از درون بعضی شبکه‌های ایرانی در دسترس است. نشانی‌ها با سایت رسمی تأیید نشده‌اند.

الکترو Electro

تابع الکترو(): وکتور<کارگزار>
دو کارگزار ساده‌ی UDP سرویس DNS الکترو. رمزشده نیستند. نشانی‌ها با سایت رسمی تأیید نشده‌اند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Servers.salam

رادار Radar

تابع رادار(): وکتور<کارگزار>
دو کارگزار ساده‌ی UDP سرویس DNS رادار. نشانی‌هایشان خصوصی است و فقط از درون بعضی شبکه‌های ایرانی در دسترس است. نشانی‌ها با سایت رسمی تأیید نشده‌اند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Servers.salam

بگزر Begzar

تابع بگزر(): وکتور<کارگزار>
دو کارگزار ساده‌ی UDP سرویس DNS بگزر. رمزشده نیستند. نشانی‌ها از یک فهرست عمومی آمده‌اند و با سایت رسمی تأیید نشده‌اند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Servers.salam

کارگزارهای ساده ایران IranPlainServers

تابع کارگزارهای ساده ایران(): وکتور<کارگزار>
شش کارگزار ساده‌ی UDP: شکن، ۴۰۳ و الکترو، برای استفاده در ایران. DNS ساده را شبکه می‌تواند بخواند و تغییر دهد، پس هر جا در دسترس‌اند کارگزارهای پیش‌فرض را ترجیح دهید.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Servers.salam

کدگذاری پاسخ EncodeResponse

تابع کدگذاری پاسخ(id: صحیح، name: رشته، qtype: صحیح، rcode: صحیح، records: وکتور<دی‌ان‌اس.رکورد>): فشرده سازی.بافر بایت
یک پیام پاسخ DNS برای یک پرسش و فهرستی از رکوردها می‌سازد. برای آزمون و کارگزار محلی هست، تا بتوان در چند سطر یک کارگزار DNS ساختگی ساخت.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Parse.salam

آزاد کردن کارگزارها FreeServers

تابع آزاد کردن کارگزارها(v &: وکتور<کارگزار>)
یک بردار کارگزار و فهرست نشانی‌هایشان را آزاد می‌کند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-doh-Servers.salam