ทำไม OpenVPN ถึงตายหลังแล็ปท็อปตื่น
การหลับอาจฆ่าเซสชัน OpenVPN และทิ้ง tun0 ไว้ ทดสอบอุโมงค์ แล้วรีสตาร์ตยูนิตจากฮุกการหลับของ systemd ไม่ใช่อุปกรณ์
ให้เครื่องเข้าสู่โหมดหลับแล้วปลุกขึ้นมา จากนั้นตรวจสามอย่างตามลำดับนี้ก่อนแตะการตั้งค่าใด ๆ ว่า tun0 ยังอยู่หรือไม่ เส้นทางไปยังที่อยู่ภายในยังเลือกมันหรือไม่ และเซิร์ฟเวอร์ยังลงทะเบียน peer นี้อยู่หรือไม่ อุปกรณ์ที่รอดจากการหลับในขณะที่เส้นทางชี้ไปที่อื่นคือเศษที่ค้างอยู่ ไม่ใช่อุโมงค์ เมื่อเส้นทางถูกต้องแต่ทราฟฟิกยังตาย ความผิดพลาดอยู่เหนืออุโมงค์และการรีสตาร์ตไคลเอนต์จะไม่เปลี่ยนสิ่งนั้น การทำให้การรีสตาร์ตเป็นอัตโนมัติจึงสมเหตุสมผลหลังจากการทดสอบด้วยมือแสดงให้เห็นแล้วว่าเป็นกรณีใดในสามกรณีนี้
ip -br address show tun0
ip route get 10.20.0.10
journalctl -u openvpn-client@office -b --no-pager | tail -30
ทำซ้ำการตื่นก่อนที่จะทำให้เป็นอัตโนมัติ
การหลับจบเซสชันที่เข้ารหัสบ่อยกว่าการลบอุปกรณ์ การไหลของ UDP ที่ทำให้อุโมงค์ยังมีชีวิตหยุดลง เซิร์ฟเวอร์อาจทิ้ง peer และไคลเอนต์อาจสังเกตเห็นแล้วเชื่อมต่อใหม่ หรือคงอินเทอร์เฟซที่ไม่มีอะไรอยู่ข้างหลัง การตรวจอินเทอร์เฟซเพียงอย่างเดียวพิสูจน์ได้น้อย เพราะ อุปกรณ์ที่ค้างเก่าดูเหมือนอุปกรณ์ที่ทำงานได้ทุกประการ จนกว่าแพ็กเก็ตจะต้องผ่านมันไป รันการค้นหาเส้นทางบวกหนึ่งคำขอจริงผ่านอุโมงค์ แล้วอ่านบันทึกช่วงเวลาที่ตื่น
ถ้าไคลเอนต์กลับมาเอง ฮุกจะเพิ่มความยุ่งยากแทนความน่าเชื่อถือ ถ้ามันไม่ฟื้นเลย การทำอัตโนมัติคือทางออกที่ซื่อสัตย์
ฮุกการหลับของ systemd อยู่ที่ไหนจริง ๆ
คู่มือเก่าหลายเล่มชี้ไปที่ /etc/pm/sleep.d ซึ่งเป็นไดเรกทอรีที่ pm-utils เป็นเจ้าของและการหลับที่ใช้ systemd ไม่เคยสอบถามเลย systemd อ่านฮุกจาก /usr/lib/systemd/system-sleep/ และ /etc/systemd/system-sleep/ โดยส่งเฟสก่อนแล้วจึงส่งการดำเนินการ ดังนั้น pre และ post จึงเป็นค่าเดียวที่ฮุกใช้แยกสาขา เก็บสำเนาไว้ใต้ /etc แทนการแก้ไขไฟล์ที่แพ็กเกจมา และจำไว้ว่าสคริปต์รันเป็น root ระหว่างการเปลี่ยนสถานะ จึงต้องกลับอย่างรวดเร็ว
#!/bin/sh
case "$1" in
post)
systemctl --no-block try-restart [email protected]
;;
esac
exit 0
try-restart แตะยูนิตเฉพาะเมื่อมันทำงานอยู่แล้ว อุโมงค์ที่คุณปิดโดยเจตนาจึงยังปิดอยู่ตลอดการตื่น --no-block กันไม่ให้ฮุกรอในขณะที่ไคลเอนต์เจรจา ซึ่งสำคัญเมื่อเครือข่ายยังไม่ขึ้น ทั้งสองแฟล็กด้วยกันหมายถึงฮุกที่ล้มเหลวอย่างเงียบ ๆ แทนที่จะหน่วงลำดับการตื่นทั้งหมด เมื่อยูนิตหยุดอยู่แล้วจะไม่มีอะไรเกิดขึ้นเลย ซึ่งเป็นผลลัพธ์ที่คุณต้องการตรงนั้น
กู้บริการและปล่อย tun0 ไว้
การลด tun0 ด้วยมือจะทิ้งให้เดมอนดูแลอินเทอร์เฟซที่มันไม่ได้เป็นเจ้าของแล้ว และการเปลี่ยนสถานะครั้งถัดไปจะสร้างข้อผิดพลาดที่สับสน ให้เล็งที่บริการหรือโปรไฟล์การเชื่อมต่อแทนอินเทอร์เฟซ ตรวจชื่อยูนิตให้แน่ชัดก่อน เพราะแพ็กเกจของดิสทริบิวชัน OpenVPN 3 และ NetworkManager ต่างเลือกชื่อที่แตกต่างกัน โปรไฟล์ NetworkManager กลับมาเมื่อการเชื่อมต่อนั้นถูกวนใหม่ ดังนั้นยูนิต systemd จึงไม่ใช่เป้าหมายตรงนั้น ไม่ว่ากลไกจะเป็นอะไร มันควรเป็นการกระทำเดียวกับที่คุณตรวจสอบด้วยมือ
การรีสตาร์ตจะติดตั้งเส้นทางที่ไคลเอนต์ดันเข้ามาเมื่อเชื่อมต่อใหม่ การตื่นส่วนใหญ่ต้องการสิ่งนั้น เครื่องที่คุณเพิ่มเส้นทางเองไม่ต้องการ ดังนั้นให้ตรวจเส้นทางเหล่านั้นใหม่แทนการถือว่าการกู้คืนคืนมันมาแล้ว และจดไว้ในที่ที่การตื่นครั้งถัดไปจะหาเจอ
จัดการจังหวะเวลาที่คุณควบคุมไม่ได้
การเชื่อมต่อไร้สายและ DHCP มักเสร็จหลังฮุกรันไปแล้ว การรีสตาร์ตจึงอาจล้มเหลวในขณะที่ยังไม่มีเส้นทางไปยังเซิร์ฟเวอร์ รอที่อยู่นั้นสักครู่ ลองอีกครั้งหนึ่ง และบันทึกผลลัพธ์
การแปลงชื่อเป็นอีกการแข่งขันหนึ่ง เพราะสแตกเครือข่ายของเดสก์ท็อปอาจคืนค่า DNS หลังจากอุโมงค์ขึ้นแล้ว ทดสอบการค้นหาแยกต่างหากด้วย resolvectl query internal.example แทนการอนุมานจากเส้นทางที่ใช้งานได้ อุโมงค์ที่กำหนดเส้นทางถูกต้องแต่ไม่แปลงอะไรเลยคือปัญหา DNS ไม่ใช่ปัญหาฮุก
ทำให้การตัดสินใจของฮุกมองเห็นได้โดยเขียนเฟส ชื่อยูนิต และผลลัพธ์ลงบันทึก จดในบันทึกของเครื่องว่าคุณรันการทดสอบการตื่นแบบใด เพื่อให้แยกการกู้คืนที่ใช้งานได้ออกจากการกู้คืนที่โชคดี เลือกการกระทำที่รบกวนน้อยที่สุดที่นำบริการกลับมา และปล่อยให้ไคลเอนต์ที่ฟื้นตัวเองได้ทำเช่นนั้น การรีสตาร์ตเต็มรูปแบบจะทิ้งเซสชันที่กำลังทำงาน ซึ่งเป็นต้นทุนจริงบนแล็ปท็อปที่ตื่นหลายครั้งต่อวัน