DNS عبر TLS - تشفير استعلامات DNS الخاصة بنا باستخدام Stunnel و Lua


مصدر الصورة


DNS (Eng. Domain Name System - نظام أسماء النطاقات) - نظام كمبيوتر موزع للحصول على معلومات حول المجالات.

TLS ( بروتوكول أمان طبقة النقل ) - يوفر نقل آمن للبيانات بين عقد الإنترنت.

بعد الأخبار "تشغيل Google Public DNS بهدوء DNS على دعم TLS" قررت أن أجربه. لدي Stunnel التي ستنشئ نفق TCP مشفر. لكن البرامج تتواصل عادةً مع DNS باستخدام بروتوكول UDP . لذلك ، نحتاج إلى وكيل يقوم بإعادة توجيه حزم UDP من وإلى دفق TCP. سنكتبها على لوا .


الفرق بين حزم TCP و UDP DNS:


4.2.2. استخدام TCP
تستخدم الرسائل المرسلة عبر اتصالات TCP منفذ الخادم 53 (عشري). تكون الرسالة مسبوقة بحقل بطول 2 بايت يعطي طول الرسالة ، باستثناء حقل بطول 2 بايت. يسمح حقل الطول هذا للمعالجة منخفضة المستوى بتجميع رسالة كاملة قبل البدء في تحليلها.

RFC1035: أسماء النطاقات - التنفيذ والمواصفات


أي أننا نفعل هناك:


  1. نأخذ حزمة من UDP
  2. أضف إليها في البداية بضع بايتات حيث يشار إلى حجم هذه الحزمة
  3. الإرسال إلى قناة TCP

وفي الاتجاه المعاكس:


  1. نقرأ بضع بايتات من TCP ، نحصل على حجم الحزمة
  2. نقرأ حزمة من TCP
  3. إرساله إلى المستلم عبر UDP

تخصيص Stunnel


  1. قم بتنزيل شهادة الجذر Root-R2.crt في الدليل بتكوين Stunnel
  2. تحويل الشهادة إلى PEM
    openssl x509 -inform DER -in Root-R2.crt -out Root-R2.pem -text 
  3. نكتب في stunnel.conf:


     [dns] client = yes accept = 127.0.0.1:53 connect = 8.8.8.8:853 CAfile = Root-R2.pem verifyChain = yes checkIP = 8.8.8.8 


أي ستونيل:


  1. سيقبل TCP غير المشفر في 127.0.0.1:53
  2. سيفتح نفق TLS مشفر لمعالجة 8.8.8.8:853 (Google DNS)
  3. سينقل البيانات ذهابا وإيابا

إطلاق Stunnel


يمكن التحقق من تشغيل النفق باستخدام الأمر:


 nslookup -vc ya.ru 127.0.0.1 

يفرض الخيار -vc nslookup على استخدام اتصال TCP بخادم DNS بدلاً من UDP.


النتيجة:


 *** Can't find server name for address 127.0.0.1: Non-existent domain Server: UnKnown Address: 127.0.0.1 Non-authoritative answer: Name: ya.ru Address: ( IP ) 

كتابة السيناريو


أكتب في لوا 5.3 . العمليات الثنائية مع الأرقام متاحة بالفعل فيه. حسنًا ، سنحتاج إلى وحدة Lua Socket .


اسم الملف: simple-udp-to-tcp-dns-proxy.lua


 local socket = require "socket" --  lua socket 

--[[--


دعنا نكتب وظيفة بسيطة تسمح لك بإرسال حزمة تفريغ إلى وحدة التحكم. أريد أن أرى ما يفعله الوكيل.


--]]--


 function serialize(data) --       az  0-9    HEX  '\xFF' return "'"..data:gsub("[^a-z0-9-]", function(chr) return ("\\x%02X"):format(chr:byte()) end).."'" end 

--[[--


UDP إلى TCP والعودة


نكتب وظيفتين ستعمل مع قناتين لنقل البيانات.


--]]--


 --    UDP   TCP  function udp_to_tcp_coroutine_function(udp_in, tcp_out, clients) repeat coroutine.yield() --     packet, err_ip, port = udp_in:receivefrom() --  UDP  if packet then -- > - big endian -- I - unsigned integer -- 2 - 2 bytes size tcp_out:send(((">I2"):pack(#packet))..packet) --       TCP local id = (">I2"):unpack(packet:sub(1,2)) --  ID  if not clients[id] then clients[id] = {} end table.insert(clients[id] ,{ip=err_ip, port=port, packet=packet}) --    print(os.date("%c", os.time()) ,err_ip, port, ">", serialize(packet)) --     end until false end --    TCP      UDP function tcp_to_udp_coroutine_function(tcp_in, udp_out, clients) repeat coroutine.yield() --     -- > - big endian -- I - unsigned integer -- 2 - 2 bytes size local packet = tcp_in:receive((">I2"):unpack(tcp_in:receive(2)), nil) --  TCP  local id = (">I2"):unpack(packet:sub(1,2)) --  ID  if clients[id] then for key, client in pairs(clients[id]) do --  query     if packet:find(client.packet:sub(13, -1), 13, true) == 13 then --   udp_out:sendto(packet, client.ip, client.port) --     UDP clients[id][key] = nil --   --     print(os.date("%c", os.time()) ,client.ip, client.port, "<", serialize(packet)) break end end if not next(clients[id]) then clients[id] = nil end end until false end 

--[[--


تقوم كلتا الوظيفتين بتنفيذ coroutine.yield () مباشرة بعد الإطلاق. يسمح لك هذا بتمرير معلمات الوظيفة إلى المكالمة الأولى ثم القيام بـ coroutine.resume (co) بدون معلمات إضافية.


الرئيسية


والآن الوظيفة الرئيسية التي ستحضر وتبدأ الحلقة الرئيسية.


--]]--


 function main() local tcp_dns_socket = socket.tcp() --  TCP  local udp_dns_socket = socket.udp() --  UDP  local tcp_connected, err = tcp_dns_socket:connect("127.0.0.1", 53) --   TCP  assert(tcp_connected, err) --    print("tcp dns connected") --      local udp_open, err = udp_dns_socket:setsockname("127.0.0.1", 53) --  UDP  assert(udp_open, err) --    print("udp dns port open") --   UDP   --     Lua        nil --              local coroutines = { [tcp_dns_socket] = coroutine.create(tcp_to_udp_coroutine_function), --   TCP to UDP [udp_dns_socket] = coroutine.create(udp_to_tcp_coroutine_function) --   UDP to TCP } local clients = {} --      --        coroutine.resume(coroutines[tcp_dns_socket], tcp_dns_socket, udp_dns_socket, clients) coroutine.resume(coroutines[udp_dns_socket], udp_dns_socket, tcp_dns_socket, clients) --    socket.select        local socket_list = {tcp_dns_socket, udp_dns_socket} repeat --    -- socket.select   socket_list          --      .  for       for _, in_socket in ipairs(socket.select(socket_list)) do --       local ok, err = coroutine.resume(coroutines[in_socket]) if not ok then --       udp_dns_socket:close() --  UDP  tcp_dns_socket:close() --  TCP  print(err) --   return --    end end until false end 

--[[--


نطلق الوظيفة الرئيسية. إذا تم إغلاق الاتصال فجأة ، فبعد ثانية سنقوم بتأسيسه مرة أخرى عن طريق الاتصال الرئيسي.


--]]--


 repeat local ok, err = coroutine.resume(coroutine.create(main)) --  main if not ok then print(err) end socket.sleep(1) --      until false 

تحقق


  1. تشغيل Stunnel


  2. قم بتشغيل البرنامج النصي الخاص بنا


     lua5.3 simple-udp-to-tcp-dns-proxy.lua 

  3. تحقق من عملية البرنامج النصي باستخدام الأمر


     nslookup ya.ru 127.0.0.1 

    هذه المرة ، بدون "-vc" ، هذه هي الطريقة التي كتبنا بها وبدءنا الوكيل ، الذي يلف طلبات UDP DNS في نفق TCP.



النتيجة:


 *** Can't find server name for address 127.0.0.1: Non-existent domain Server: UnKnown Address: 127.0.0.1 Non-authoritative answer: Name: ya.ru Address: ( IP ) 

إذا كان كل شيء على ما يرام ، يمكنك تحديد إعدادات الاتصال كخادم DNS "127.0.0.1"


الاستنتاج


الآن محمية استعلامات DNS الخاصة بنا بواسطة TLS .


ملاحظة: نحن لا نعطي google معلومات إضافية عنا


بعد الاتصال مباشرة ، يحاول Windows تسجيلنا على خوادم DNS الخاصة بـ Google عبر نفقنا. تم تعطيل هذا في إعدادات DNS المتقدمة عن طريق إلغاء التحديد.



لا يزال هناك طلب لموقع time.windows.com. لم يعد شخصيًا بعد الآن ، لكنني لم أجد أبدًا كيفية إيقاف تشغيله. تم تعطيل المزامنة التلقائية للوقت.


الروابط


  1. RFC1035: أسماء النطاقات - التنفيذ والمواصفات
  2. DNS عبر TLS
  3. simple-udp-to-tcp-dns-proxy.lua
  4. إنشاء استعلام DNS يدويًا

Source: https://habr.com/ru/post/ar427957/


All Articles