ฮุก PHP ของ OpenVPN: trusted_ip กับ ifconfig_pool_remote_ip
สองที่อยู่ที่มีความหมายต่างกันสองอย่าง อ่านโดยกระบวนการที่คุณไม่ได้เริ่ม สิ่งที่ตัวแปรฮุกคืออะไร และทำไม $_ENV ที่ว่างเปล่าจึงไม่ได้พิสูจน์อะไรเลย
อาร์เรย์ $_ENV ที่ว่างเปล่าในสคริปต์ฮุกดูเหมือนเป็นหลักฐานว่า OpenVPN ไม่ได้ส่งอะไรมาที่จริงโดยปกติแล้วมันพิสูจน์อย่างอื่นเลย: PHP ถูกกำหนดค่าให้ไม่เติมซูเปอร์โกลบอลนั้น และค่าต่างๆ อยู่ในสภาพแวดล้อมของกระบวนการตลอดเวลา ข้อสรุปผิดข้อที่สองนั้นละเอียดกว่ามาก เพราะตัวแปรที่อยู่สองตัวในฮุกการเชื่อมต่อมีความหมายต่างกันและถูกใช้สลับกันไปมา ความผิดพลาดทั้งสองอย่างทำให้เสียเวลาครึ่งวันถ้าเริ่มจากตัวที่ผิด
สองที่อยู่ สองข้อกล่าวอ้างที่ต่างกัน
ปลายทางภายนอกคือสิ่งที่เซิร์ฟเวอร์สังเกตเมื่อไคลเอนต์เชื่อมต่อ เข้าถึงได้ในชื่อ trusted_ip สำหรับ IPv4 และ trusted_ip6 สำหรับ IPv6 ที่อยู่เสมือนคือสิ่งที่พูลจัดสรรให้กับเซสชันนี้ เข้าถึงได้ในชื่อ ifconfig_pool_remote_ip
ทั้งสองตอบคำถามคนละอย่าง และบันทึกมักต้องการเพียงอย่างใดอย่างหนึ่ง ไม่ใช่ทั้งสอง ตัวแรกคือที่มาของการเชื่อมต่อ ซึ่งอาจเป็นที่อยู่ NAT ที่ใช้ร่วมกันโดยคนหลายร้อยคน ตัวที่สองคือตำแหน่งของเซสชันนี้ภายในอุโมงค์ และสามารถจัดสรรให้เซสชันอื่นได้ในภายหลัง การสับสนระหว่างสองสิ่งนี้ทำให้ได้บันทึกที่ดูสมเหตุสมผลแต่ผิด
การอ่านขั้นต่ำมีหน้าตาเช่นนี้
$outer4 = getenv('trusted_ip');
$outer6 = getenv('trusted_ip6');
$inner = getenv('ifconfig_pool_remote_ip');
$outer = $outer4 !== false ? $outer4 : $outer6;ไม่มีค่าใดระบุตัวบุคคลได้ อย่างหนึ่งคือการสังเกตจากเครือข่าย อีกอย่างหนึ่งคือสัญญาเช่า และบันทึกที่ถือค่าใดค่าหนึ่งเป็นตัวระบุอุปกรณ์ถาวรจะผิดตั้งแต่ครั้งแรกที่ไคลเอนต์เชื่อมต่อใหม่จากเครือข่ายอื่นหรือได้รับที่อยู่พูลอื่น เลือกฟิลด์ตามคำถามที่บันทึกต้องตอบ แล้วเขียนคำถามนั้นไว้ข้างคอลัมน์
ตรวจสอบว่า PHP ถูกเริ่มอย่างไร ไม่ใช่เชลล์ของคุณ
ฮุกรันเป็นลูกของเดมอน VPN ด้วยสภาพแวดล้อมที่เดมอนสร้างขึ้น เชลล์แบบโต้ตอบของคุณมีสภาพแวดล้อมอื่น และการรันสคริปต์ด้วยมือนั้นทดสอบสภาพแวดล้อมของเชลล์ ไม่ใช่ของฮุก
เริ่มด้วยการยืนยันว่าฮุกทำงานจริงในขั้นตอนที่คุณคาดหวัง สคริปต์ที่ผูกกับขั้นตอนผิด หรือตัวที่ไม่เคยรันเพราะไดเรกทีฟชี้ไปยังเส้นทางอื่น ให้อาการเหมือนกันทุกประการกับตัวแปรที่หายไป เพิ่มบรรทัดเครื่องหมายโดยเจตนาไว้บนสุดของสคริปต์ และยืนยันว่ามันปรากฏก่อนที่คุณจะตรวจสอบสิ่งอื่น บรรทัดเดียวที่มีการประทับเวลาในบันทึกแยก «ไม่เคยรัน» ออกจาก «รันโดยไม่มีค่า»
จากนั้นยืนยันว่าการเรียกใช้นั้นใช้ตัวแปลภาษาและไฟล์กำหนดค่าใด การแก้ไขการกำหนดค่า PHP สำหรับเว็บเซิร์ฟเวอร์ไม่ได้เปลี่ยนอะไรกับกระบวนการ CLI ที่ OpenVPN เริ่ม และทั้งสองอาจโหลดไฟล์ php.ini ที่ต่างกันโดยสิ้นเชิง
ทำไม $_ENV ที่ว่างเปล่าจึงไม่ได้พิสูจน์อะไร
PHP เอกสารอ้างอิง getenv อธิบายการอ่านสภาพแวดล้อมของกระบวนการโดยตรง ซึ่งคืนค่า false เมื่อไม่มีชื่อนั้น ซูเปอร์โกลบอล $_ENV ถูกเติมแยกต่างหาก และไดเรกทีฟ variables_order ตัดสินว่าซูเปอร์โกลบอลใดจะถูกเติม
ถ้าไดเรกทีฟนั้นละเว้น E $_ENV จะยังคงว่างเปล่าไม่ว่าสภาพแวดล้อมจะมีอะไรก็ตาม โค้ดที่ทำดัชนีมันจะรายงานตัวแปรที่หายไปซึ่งจริงๆ แล้วมีอยู่ และการสอบสวนจะมุ่งไปที่ OpenVPN ขณะที่คำตอบอยู่ใน php.ini ตรวจสอบไดเรกทีฟสำหรับการกำหนดค่า CLI โดยเฉพาะ ไม่ใช่สำหรับเว็บเซิร์ฟเวอร์
การอ่านด้วย getenv หลีกเลี่ยงความสับสนทั้งหมดนี้ และสคริปต์ห่อที่ล้างสภาพแวดล้อมก่อนเรียกตัวแปลภาษาจะนำมันกลับมาในอีกรูปแบบหนึ่ง
เก็บความสัมพันธ์ ไม่ใช่การอัปเดตแถว
ตัดสินใจว่าบันทึกต้องการค่าใดก่อนเขียน ถ้าเป้าหมายคือบันทึกว่าเซสชันมาจากไหน ให้เก็บปลายทางภายนอกและติดป้ายว่าเป็นการสังเกต ถ้าเป้าหมายคือจับคู่เซสชันกับที่อยู่ของอุโมงค์ตลอดช่วงการเชื่อมต่อ ให้เก็บที่อยู่พูลและผูกกับเซสชัน
อัปเดตตามตัวตนที่ผ่านการรับรองและเซสชันปัจจุบัน ไม่ใช่ตามทุกแถวที่ใช้ที่อยู่ของอุโมงค์ร่วมกัน เพราะที่อยู่พูลถูกใช้ซ้ำ และเหตุการณ์ตัดการเชื่อมต่อที่มาช้าอาจเขียนทับข้อมูลของการเชื่อมต่อใหม่กว่า จัดการ IPv6 อย่างชัดเจนแทนที่จะเขียนเฉพาะค่า IPv4 อย่างเงียบๆ แถวที่มีที่อยู่ภายนอกเป็น NULL ดีกว่าแถวที่มีที่อยู่ผิด เพราะแถวแรกเห็นได้ชัดว่าไม่สมบูรณ์
ผูกการเขียนกับตัวระบุเซสชันที่ OpenVPN ให้มา เพื่อให้การเชื่อมต่อใหม่สร้างบันทึกใหม่แทนที่จะแก้ไขของเก่า ใช้คำสั่งที่มีพารามิเตอร์และบัญชีที่มีเฉพาะสิทธิ์ที่การดำเนินการต้องการ ฮุกรันด้วยอำนาจของเดมอน ดังนั้นคำสั่งค้นหาที่ไม่ระวังจึงเป็นปัญหาที่ใหญ่กว่าบรรทัดบันทึกที่ผิด
วินิจฉัยโดยไม่เทสภาพแวดล้อมทิ้ง
บันทึกว่ามีชื่อใดอยู่ ขั้นตอนใดทำงาน และใช้ตัวแปลภาษาใด ห้ามพิมพ์สภาพแวดล้อมทั้งหมด เพราะกระบวนการฮุกอาจสืบทอดค่าที่ไม่เกี่ยวข้องซึ่งไม่ควรไปอยู่ในไฟล์บันทึก
ตรวจสอบการเชื่อมต่อหนึ่งครั้งตั้งแต่ต้นจนจบ: อ่านปลายทางภายนอก อ่านที่อยู่ที่ได้รับมอบหมาย และยืนยันทั้งสองกับมุมมองของเซิร์ฟเวอร์เองเกี่ยวกับเซสชันนั้น เมื่อยืนยันคู่ได้สำหรับไคลเอนต์หนึ่งรายแล้ว ก็ไว้วางใจความสัมพันธ์นั้นที่อื่นได้