Wednesday, June 23, 2010

How to change resolver configuration file?

Q: How to change resolver configuration file?
A: I don't know.

ตรงนี้ขอเกริ่นนำกับบ่นๆๆๆๆ ก่อนนะครับ
อยากรู้วิธีแก้ path ของไฟล์คอนฟิก ข้ามไปอ่านข้างล่างได้เลยครับ
เมื่อประมาณต้นปีผมต้องเขียนโปรแกรมนึงให้มันไปเปลี่ยน dns server ของระบบ (FreeBSD) ที่โดนตั้งไว้ ปัญหาคือตอนที่ FreeBSD จะทำการ nslookup ไปที่ dns server มันจะอ่านไฟล์คอนฟิกนึงว่า dns server ของเราคือเครื่องไหน ไฟล์นั้นก็คือ /etc/resolv.conf ซึ่งมันจะอ่านทุกครั้งที่เราจะ nslookup!!! (ใส่เครื่องหมายตกใจทำไม อ้าว ไม่ตกใจเหรอครับ เพราะผมไม่รู้มาก่อน นึกว่ามันจะทำการโหลดค่ามาเก็บไว้ตอนบู๊ทเครื่องทีเดียว ไม่คิดว่ามันจะอ่านไฟล์ใหม่ทุกครั้ง)

เนื่องจากว่านโยบายในการเขียนโปรแกรมครั้งนั้นมีอยู่ว่า โปรแกรมของผมจะไม่แตะต้องไฟล์ใน /etc เพราะมันเป็นไฟล์ของระบบ ถ้าเกิดทำอะไรเสียหายไปเดี๋ยวจะเดือดร้อน (/etc ของ appliance ในความคิดผมควรจะเป็น read-only) ซึ่งจากประสบการณ์ที่ได้แตะเซอร์วิสของ FreeBSD มาบ้าง เซอร์วิสส่วนใหญ่เราสามารถระบุได้ว่าจะให้มันไปอ่านไฟล์คอนฟิกที่ไหน (ระบุได้จากหลายๆทาง เช่น environment variable ฯลฯ) หรือไม่ก็สามารถคอนฟิกในไฟล์คอนฟิกให้มัน include ไฟล์คอนฟิกอื่นเพิ่มเข้าไปได้ เราก็จะได้เขียนไฟล์คอนฟิกนั้นแค่ทีเดียวแล้วไปแก้ไฟล์คอนฟิกอื่นๆที่ include เข้าไปแทน

หลังจากการค้นหาอยู่นานผมก็ค้นพบวิธีการที่ทำให้มันไม่ต้องยุ่งกับ /etc/resolv.conf ได้ด้วยการ
...
...
เลิกเขียนโปรแกรมซะ

โว้ย ทำไมมันไม่มีวิธีวะ หาแทบพลิกแผ่นดินแล้ว สุดท้ายโปรแกรมของผมก็จำต้องไปแก้ไขไฟล์ /etc/resolv.conf ไปก่อนเพราะงานมันเร่งต้องส่งลูกค้าแล้ว

แล้วช่วงนี้ต้องกลับมาแก้ไขโครงสร้างของระบบใหม่ คราวนี้ได้รับคำสั่งมาว่า /etc ต้องโดน mount เป็น read-only ก็เลยต้องกลับมาค้นดูอีกทีว่าจะทำไงดี หลังจากถามพี่ที่บริษัทก็พบว่าตัว resolver ของ FreeBSD นั้นมันใส่ชื่อไฟล์ลงไปในโค้ดเลย โอ้ว แม่เจ้า ทำงี้ได้ไงฟระ

วิธีแก้
หลังจากที่ไล่โค้ดดู (อยู่ใน /usr/include/resolv.h) ก็เห็นส่วนที่ไว้ระบุไฟล์คอนฟิก มันระบุโดยการใช้ define เอาครับ ดังนั้นเราสามารถ define ค่าของตัวแปรใหม่ได้ตอนสั่งคอมไพล์ ค่อยยังชั่วหน่อย ไม่ต้องแก้โค้ด แต่ว่าเราก็ไม่สามารถเปลี่ยน path ของไฟล์คอนฟิกแบบ dynamic ได้อยู่ดี (โลกนี้มันช่างโหดร้ายจริงๆ)

ตัวแปรที่ไว้กำหนด path ของไฟล์คอนฟิกของ resolver นั้นชื่อว่า

_PATH_RESCONF

ขั้นตอนต่อไป เดี๋ยวจะลองคอมไพล์โดย define ตัวแปรนี้ชี้ไปที่อื่นดู
ตัวผมเองก็ไม่เคยคอมไพล์เคอเนลโดยใส่ออปชันอะไรแบบนี้มาก่อนเหมือนกัน ยังไม่ค่อยแน่ใจว่าต้องใส่ยังไง เดี๋ยวลองเสร็จแล้วจะมาสรุปอีกที

1 comment:

Unknown said...

วิธีนี้เราลองมาแล้ว ใช้ไม่ได้ผลหรอก จากแบ... เอ้ย


แก้แค่นี้ต้อง compile Kernel เลยเหรอวะ o__o' ก็ตั้ง _PATH_RESCONF ตอนคอมไพล์ให้มันชี้ไป local file ที่แก้ได้ง่ายๆ หรือไม่ก็ #define ทับไปเลยใน code (#define _PATH_RESCONF my_string_var) โดยให้มั่นใจว่าไฟล์นี้มันโดน include หลัง resolv.h ได้ปล่าว ?

search มาคร่าวๆ (จริงๆก็ไม่คร่าวเท่าไหร่) มันบอกว่าไฟล์ _PATH_RESCONF นี้โดนอ่านตอน res_init โดนเรียกครั้งแรก (http://www.gsp.com/cgi-bin/man.cgi?section=3&topic=res_init) หลังจากแก้ local file หรือ my_string_var แล้วจะให้ refresh DNS ก็เรียก res_init อีกรอบก็ได้ อันนี้ก็น่าอ่าน http://myhowto.org/java/42-understanding-host-name-resolution-and-dns-behavior-in-java/

งานคุณโคดกีk เลยว่ะ