บางสิ่งเกี่ยวกับ getaddrinfo ที่ทำให้ฉันประหลาดใจ

สวัสดี! ต่อไปนี้คือบางสิ่งที่คุณอาจหรืออาจไม่ได้สังเกตเกี่ยวกับ DNS:

  • เมื่อคุณแก้ไขชื่อ DNS ในโปรแกรม Python โปรแกรมจะตรวจสอบ /etc/hosts แต่เมื่อคุณใช้ dig จะไม่ตรวจสอบ
  • การเปลี่ยนการกระจาย Linux ในบางครั้งสามารถเปลี่ยนวิธีการทำงานของ DNS ของคุณได้ ตัวอย่างเช่น หากคุณใช้ Alpine Linux แทน Ubuntu ก็อาจทำให้เกิดปัญหาได้
  • Mac OS มีการแคช DNS แต่ Linux ไม่จำเป็น เว้นแต่คุณจะใช้ systemd-resolved หรือบางอย่าง

เพื่อทำความเข้าใจสิ่งเหล่านี้ เราจำเป็นต้องเรียนรู้เกี่ยวกับฟังก์ชันที่เรียกว่า getaddrinfo ซึ่งมีหน้าที่รับผิดชอบในการค้นหา DNS

มีหลายสิ่งที่น่าประหลาดใจสำหรับฉันเกี่ยวกับ getaddrinfo และเมื่อฉันได้เรียนรู้เกี่ยวกับสิ่งเหล่านี้ มันจะอธิบายพฤติกรรม DNS ที่สับสนหลายอย่างที่ฉันเคยเห็นในอดีต

getaddrinfo มาจากไหน?

getaddrinfo เป็นส่วนหนึ่งของไลบรารีที่เรียกว่า libc ซึ่งเป็นไลบรารี C มาตรฐาน มี libc อย่างน้อย 3 เวอร์ชัน:

  1. glibc (GNU libc)
  2. musl libc
  3. libc เวอร์ชัน Mac OS (ฉันไม่รู้ว่าชื่อนี้มีหรือเปล่า)

มีอีกมากอย่างแน่นอน (ฉันคิดว่า FreeBSD และ OpenBSD ต่างก็มีเวอร์ชันของตัวเอง เป็นต้น) แต่นั่นคือ 3 สิ่งที่ฉันรู้

แต่ละคนมี getaddrinfo เวอร์ชันของตนเอง

ไม่ใช่ทุกโปรแกรมที่ใช้ getaddrinfo สำหรับ DNS

สิ่งแรกที่ฉันพบว่าน่าประหลาดใจคือ getaddrinfo มีการใช้กันอย่างแพร่หลายแต่ไม่ได้ใช้อย่างแพร่หลาย

ทุกโปรแกรมมีพื้นฐาน 2 ตัวเลือก:

  1. ใช้ getaddrinfo ฉันคิดว่า Python, Ruby และ Node ใช้ getaddrinfo เช่นเดียวกับ Go ในบางครั้ง อาจมีหลายภาษามากกว่านี้ด้วย แต่ฉันไม่มีเวลาค้นหาไลบรารี DNS ของทุกภาษา
  2. ใช้ฟังก์ชันตัวแก้ไข DNS ที่กำหนดเอง ตัวอย่างของสิ่งนี้:
    • ขุด. ฉันคิดว่าเป็นเพราะ dig ต้องการการควบคุมมากกว่าการสืบค้น DNS มากกว่าที่ getaddrinfo รองรับ ดังนั้นจึงใช้ตรรกะ DNS ของตัวเอง
    • Go ยังมีตัวแก้ไข DNS แบบ Pure-Go หากคุณไม่ต้องการใช้CGo
    • มี Ruby gem ที่มี ตัวแก้ไข DNS แบบกำหนดเอง ที่คุณสามารถใช้เพื่อแทนที่ getaddrinfo
    • getaddrinfo ไม่รองรับ DNS ผ่าน HTTPS ดังนั้นฉันคิดว่าเบราว์เซอร์ที่ใช้ DoH ไม่ได้ใช้ getaddrinfo สำหรับการค้นหา DNS เหล่านั้น
    • คงอีกมากที่ฉันไม่รู้

บางครั้งคุณจะเห็น getaddrinfo ในข้อความแสดงข้อผิดพลาด DNS ของคุณ

เนื่องจากมีการใช้ getaddrinfo อย่างแพร่หลาย คุณจึงมักจะเห็นในข้อความแสดงข้อผิดพลาดที่เกี่ยวข้องกับ DNS

ตัวอย่างเช่น ถ้าฉันเรียกใช้โปรแกรม Python ซึ่งค้นหาชื่อโดเมนที่ไม่มีอยู่:

 import requests requests.get("http://xyxqqx.com")

ฉันได้รับข้อความแสดงข้อผิดพลาดนี้:

 Traceback (most recent call last): File "/usr/lib/python3.10/site-packages/urllib3/connection.py", line 174, in _new_conn conn = connection.create_connection( File "/usr/lib/python3.10/site-packages/urllib3/util/connection.py", line 72, in create_connection for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM): File "/usr/lib/python3.10/socket.py", line 955, in getaddrinfo for res in _socket.getaddrinfo(host, port, family, type, proto, flags): socket.gaierror: [Errno -2] Name or service not known

ฉันคิดว่า socket.getaddrinfo กำลังเรียก libc getaddrinfo ที่ไหนสักแห่งภายใต้ประทุน แม้ว่าฉันไม่ได้อ่านซอร์สโค้ดทั้งหมดเพื่อตรวจสอบ

ก่อนที่คุณจะเรียนรู้ว่า getaddrinfo คืออะไร ไม่ชัดเจนเลยที่ socket.gaierror: [Errno -2] Name or service not known หมายความว่า “ไม่มีโดเมนนั้น” มันไม่แม้แต่จะพูดคำว่า “DNS” หรือ “โดเมน” ได้ทุกที่!

getaddrinfo บน Mac ไม่ได้ใช้ /etc/resolv.conf

ฉันเคยใช้ Mac ในการทำงาน และมักจะรู้สึกไม่มั่นคงโดย DNS บน Mac ฉันสามารถบอกได้ว่ามี บางอย่าง ที่แตกต่างจากวิธีการทำงานบนเครื่อง Linux ของฉัน แต่ฉันไม่รู้ว่ามันคืออะไร

ฉันยังไม่เข้าใจสิ่งนี้ทั้งหมด และเป็นการยากสำหรับฉันที่จะตรวจสอบ เพราะขณะนี้ฉันไม่สามารถเข้าถึง Mac ได้ แต่นี่คือสิ่งที่ฉันได้รวบรวมมาจนถึงตอนนี้

บนระบบ Linux getaddrinfo ตัดสินใจว่าตัวแก้ไข DNS ตัวใดที่จะพูดคุยกับโดยใช้ไฟล์ชื่อ /etc/resolv.conf (เห็นได้ชัดว่ามีความซับซ้อนเพิ่มเติมบางอย่างกับ /etc/nsswitch.conf แต่ฉันไม่เคยดู /etc/nsswitch.conf ดังนั้นฉันจะไม่สนใจมัน)

ตัวอย่างเช่น นี่คือเนื้อหาของ /etc/resolv.conf ของฉันตอนนี้:

 # Generated by NetworkManager nameserver 192.168.1.1 nameserver fd13:d987:748a::1

ซึ่งหมายความว่าในการสอบถาม DNS นั้น getaddrinfo จะส่งคำขอไปที่ 192.168.1.1 บนพอร์ต 53 นั่นคือตัวแก้ไข DNS ของเราเตอร์ของฉัน

ฉันคิดว่านี่เป็น getaddrinfo บน Mac และเพิ่งใช้ /etc/resolv.conf แต่ฉันคิดผิด แต่ getaddrinfo ส่งคำขอไปยังโปรแกรมที่เรียกว่า mDNSResponder ซึ่งเป็นของ Mac

ฉันไม่รู้อะไรมากเกี่ยวกับ mDNSResponder ยกเว้นว่าทำการแคช DNS และเห็นได้ชัดว่าคุณสามารถล้างแคชด้วย dscacheutil ได้ สิ่งนี้อธิบายความลึกลับอย่างหนึ่งในตอนต้นของโพสต์ – เหตุใด Macs จึงมีการแคช DNS และเครื่อง Linux ไม่เสมอไป

musl libc getaddrinfo นั้นแตกต่างจากเวอร์ชันของ glibc

คุณอาจคิดว่าโอเค Mac OS getaddrinfo ต่างกัน แต่ getaddrinfo สองเวอร์ชันใน glibc และ musl libc ส่วนใหญ่จะต้องเหมือนกันใช่ไหม

แต่พวกเขามีความแตกต่างที่สำคัญทีเดียว ความแตกต่างหลักที่ฉันรู้คือ musl libc ไม่รองรับ TCP DNS ฉันไม่พบสิ่งใดในเอกสารเกี่ยวกับมัน แต่มีการกล่าวถึงใน ทวีตนี้ )

ฉันได้พูดเพิ่มเติมเกี่ยวกับสิ่งนี้ TCP DNS ใน ลักษณะที่ DNS สามารถทำลาย ได้

ความแตกต่างเพิ่มเติมบางประการ:

  • วิธีจัดการโดเมนการค้นหา (ใน /etc/resolv.conf ) แตกต่างกันเล็กน้อย ( กล่าวถึงที่นี่ )
  • โพสต์นี้ระบุว่า musl ไม่รองรับ nsswitch.conf ฉันไม่เคยใช้ nsswitch.conf และไม่รู้ว่าทำไมมันถึงมีประโยชน์ แต่ฉันคิดว่ามีเหตุผลที่ฉันไม่รู้

สิ่งแปลก ๆ เพิ่มเติม: nscd?

เมื่อค้นหา getaddrinfo ฉันยังพบ โพสต์ที่น่าสนใจเกี่ยวกับ getaddrinfo จาก James Fisher ที่ติดตาม glibc getaddrinfo และพบว่าเห็นได้ชัดว่าเรียกโปรแกรมบางตัวที่เรียกว่า nscd ซึ่งควรจะทำการแคช DNS โพสต์บล็อกนั้นอธิบาย nscd ว่า “ไม่เสถียร” และ “ออกแบบมาไม่ดี” และฉันไม่ชัดเจนว่ามีการใช้กันอย่างแพร่หลายเพียงใด

ฉันไม่รู้อะไรเกี่ยวกับ nscd แต่ฉันตรวจสอบแล้ว และเห็นได้ชัดว่ามันอยู่ในคอมพิวเตอร์ของฉัน ฉันลองแล้วนี่คือสิ่งที่เกิดขึ้น:

 $ nscd child exited with status 4

ความประทับใจของฉันคือผู้ที่ต้องการแคช DNS บน Linux มักจะใช้ตัวส่งต่อ DNS เช่น dnsmasq หรือ systemd-resolved resolved แทนที่จะใช้ nscd นั่นคือสิ่งที่ฉันเห็นในอดีต

นั่นคือทั้งหมด!

เมื่อฉันเรียนรู้เกี่ยวกับทั้งหมดนี้เป็นครั้งแรก ฉันพบว่ามันน่าแปลกใจจริงๆ ที่ฟังก์ชันไลบรารีที่ใช้กันอย่างแพร่หลายนั้นมีพฤติกรรมที่แตกต่างกันออกไปบนแพลตฟอร์มต่างๆ

ฉันหมายความว่า มันสมเหตุสมผลแล้วที่คนที่สร้าง Mac OS จะต้องการจัดการแคช DNS ด้วยวิธีที่ต่างไปจากที่จัดการบน Linux ดังนั้นจึงสมเหตุสมผลที่พวกเขาใช้ getaddrinfo ต่างกัน และมันก็สมเหตุสมผลที่บางโปรแกรมเลือกที่จะไม่ใช้ getaddrinfo เพื่อทำการสืบค้น DNS

แต่มันทำให้ DNS ยากขึ้นเล็กน้อยที่จะให้เหตุผล

ใส่ความเห็น

อีเมลของคุณจะไม่แสดงให้คนอื่นเห็น