เชื่อมไคลเอนต์ OpenVPN สองตัวบนโฮสต์ Linux เครื่องเดียวด้วย fwmark
ไคลเอนต์ทั้งสองต้องการเส้นทางเริ่มต้น ปักหมุดเซิร์ฟเวอร์ภายในด้วยโฮสต์รูต หยุดไคลเอนต์ที่สองไม่ให้เขียนตารางใหม่ แล้วจึงกำหนดเส้นทางโฟลว์ด้วย fwmark
การวางไคลเอนต์ OpenVPN ตัวที่สองซ้อนบนโฮสต์ Linux เครื่องเดียวล้มเหลวได้ในหนึ่งในสองจุด คือไคลเอนต์ภายในไปถึงเซิร์ฟเวอร์ของตัวเองไม่ได้ เพราะอุโมงค์ภายนอกได้ครอบการรับส่งนั้นไปแล้ว หรือไคลเอนต์ที่สองเขียนตารางเส้นทางใหม่และอุโมงค์แรกหยุดทำงาน ปัญหาทั้งสองอยู่ที่การกำหนดเส้นทาง ไม่ใช่การเข้ารหัส และทั้งสองแก้ได้ก่อนที่อุโมงค์ใหม่จะรับส่งข้อมูลแอปพลิเคชันใด ๆ ที่อยู่นี้เป็นตัวอย่าง: tun0 คืออุโมงค์ภายนอก 203.0.113.9 คือเซิร์ฟเวอร์ภายใน และ TCP 9999 คือโฟลว์ที่ต้องใช้เส้นทางภายใน
สองโหมดความล้มเหลว หนึ่งตารางเส้นทาง
ไคลเอนต์ภายในเปิดซ็อกเก็ต UDP ไปยังเซิร์ฟเวอร์ของตน และซ็อกเก็ตนั้นเดินตามตารางเส้นทางปัจจุบันเหมือนตัวอื่น ๆ หากอุโมงค์ภายนอกถือเส้นทางเริ่มต้นอยู่แล้ว แพ็กเก็ตแฮนด์เชกจะเข้าไปในอุโมงค์ภายนอก สิ่งนี้ใช้ได้เฉพาะเมื่อเซิร์ฟเวอร์ภายนอกเข้าถึงเซิร์ฟเวอร์ภายในได้และอีกฝั่งตกลงรับโฟลว์นั้น มิฉะนั้นแฮนด์เชกจะค้างและไคลเอนต์ลองใหม่
ความล้มเหลวที่สองมาจาก push ของเซิร์ฟเวอร์ push ที่ใช้กันทั่วไปคือ redirect-gateway def1 ซึ่งติดตั้ง 0.0.0.0/1 และ 128.0.0.0/1 แทนการแทนที่เส้นทางเริ่มต้น ไคลเอนต์สองตัวที่แต่ละตัวติดตั้งคู่ /1 ของตัวเองจึงชนกัน และคู่ที่ใหม่ที่สุดชนะสำหรับเกือบทุกปลายทาง ให้มองหาคำนำหน้าสองตัวนั้นในตารางเมื่ออุโมงค์ตายหลังจากตัวที่สองเชื่อมต่อ เพราะเส้นทางเริ่มต้นเองอาจไม่เคยเปลี่ยนเลย
ทำเครื่องหมายโฟลว์และให้ตารางแก่โฟลว์นั้น
กำหนดเส้นทางให้ทราฟฟิกที่เลือกโดยทำเครื่องหมายในตาราง mangle และจับคู่เครื่องหมายในกฎนโยบาย กฎชี้ไปยังตารางเฉพาะที่มีเส้นทางเริ่มต้นเป็นอุปกรณ์ภายใน แพ็กเก็ตที่ทำเครื่องหมายแล้วเท่านั้นจึงใช้เส้นทางภายใน
iptables -t mangle -A PREROUTING -p tcp -m multiport --dport 9999 -j MARK --set-mark 0x9999
ip rule add fwmark 0x9999 table 200 pref 1000
ip route add default dev tun1 table 200ความล้มเหลวส่วนใหญ่ในชุดกฎนี้มาจากสองข้อผิดพลาด ค่าเครื่องหมายที่ไฟร์วอลล์ตั้งและค่าที่กฎจับคู่ต้องเหมือนกัน เพราะความไม่ตรงกันไม่ก่อทั้งข้อผิดพลาดและผลลัพธ์ และ PREROUTING เห็นเฉพาะแพ็กเก็ตที่มาจากภายนอก การเชื่อมต่อที่เริ่มบนโฮสต์นี้จึงต้องมีกฎ OUTPUT ที่จับคู่เหมือนกันก่อนจะถูกทำเครื่องหมายเลย
ยึดความเป็นเจ้าของเส้นทางคืนจากไคลเอนต์ที่สอง
สองตัวเลือกป้องกันไม่ให้ไคลเอนต์ที่สองแก้ไขตาราง และทำงานต่างจุดกัน route-nopull ไม่สนใจตัวเลือกเส้นทางที่ถูก push จึงไม่มีอะไรถูกติดตั้ง route-noexec รับตัวเลือกที่ถูก push เข้าสภาพแวดล้อมของไคลเอนต์ แต่ปล่อยการเปลี่ยนตารางให้ hook ซึ่งเป็นสิ่งที่คุณต้องการเมื่อต้องดูว่าเซิร์ฟเวอร์เสนออะไร
hook ทำงานด้วยค่าที่ถูก push ในสภาพแวดล้อมของมัน และควรเพิ่มเฉพาะรายการที่คุณอนุมัติ ทำให้มัน idempotent: ล้างตารางที่มันถืออยู่ก่อนสร้างใหม่ และอย่าถือว่าการรันครั้งก่อนทิ้งสภาพที่สะอาดไว้ การเชื่อมต่อใหม่เรียก hook อีกครั้ง และ hook ที่เพิ่มโดยไม่ล้างจะสะสมเส้นทางซ้ำ
เลือกเจ้าของเพียงหนึ่งเดียวและเขียนมันลงไป โปรไฟล์ที่ตั้งทั้งสองตัวเลือก หรือ hook ที่แข่งขันกับสคริปต์มือ จะสร้างตารางที่ไม่มีใครอธิบายได้ในภายหลัง
ปักหมุดที่อยู่เซิร์ฟเวอร์ทั้งสอง
เซิร์ฟเวอร์ภายในต้องมีโฮสต์รูตผ่านอุปกรณ์ภายนอกก่อนที่ไคลเอนต์ภายในจะเชื่อมต่อ รายการนั้นคือสิ่งที่เก็บการรับส่งภายในไว้ในอุโมงค์ภายนอกแทนที่จะปล่อยให้เดินตามเส้นทางเริ่มต้น
ip route add 203.0.113.9/32 dev tun0
ip route get 203.0.113.9เพิ่มโฮสต์รูตที่ตรงกันสำหรับเซิร์ฟเวอร์ภายนอกในตารางหลักด้วย มิฉะนั้นการเชื่อมต่อใหม่อาจกำหนดเส้นทางของการรับส่งของไคลเอนต์ภายนอกเองเข้าไปในอุโมงค์ของมัน ลำดับไม่ใช่ทางเลือก: เพิ่มรายการเหล่านี้หลังจากอินเทอร์เฟซที่เกี่ยวข้องมีอยู่แล้ว ซึ่งหมายถึง hook หรือสคริปต์ที่รันหลังเชื่อมต่อ เส้นทางที่ชี้ไปยังอุปกรณ์ที่ดับอยู่จะถูกลบหรือถูกละเลย รายการที่เขียนตอนบูตจึงไม่รอดผ่านลำดับที่คุณสมมติไว้
ตรวจสอบการค้นหาแทนการอ่านทั้งตาราง เอาต์พุตของการค้นหาเส้นทางระบุอุปกรณ์และที่อยู่ต้นทางที่เคอร์เนลจะใช้ และนั่นคือสิ่งที่ไคลเอนต์ได้รับเมื่อเปิดซ็อกเก็ตของตน
ทดสอบห่วงโซ่และทำให้ความล้มเหลวมองเห็นได้
ดักจับบนอินเทอร์เฟซภายนอกขณะไคลเอนต์ภายในเชื่อมต่อ แฮนด์เชกภายในควรปรากฏเป็นเพย์โหลดที่เข้ารหัสอยู่ในอุโมงค์ภายนอก หากปรากฏเป็น UDP ธรรมดาไปยัง 203.0.113.9 แสดงว่าไม่มีโฮสต์รูตและห่วงโซ่ไม่เคยถูกสร้าง
ห่วงโซ่ที่ย้อนกลับไปยังอัปลิงก์กายภาพอย่างเงียบ ๆ คือผลลัพธ์ที่แย่ที่สุด เพราะสถานะอินเทอร์เฟซไม่ได้ประกาศอะไรและทราฟฟิกภายในออกจากที่อยู่ต้นทางผิด หากไคลเอนต์ที่สองเชื่อมต่อใหม่โดยตรงได้เมื่ออุโมงค์ภายนอกหลุด ให้ปิดเส้นทางนั้นหรือผูกกับอินเทอร์เฟซภายนอกเพื่อให้ความล้มเหลวมองเห็นได้
ปิดท้ายด้วยสองโฟลว์และการดัมป์กฎหนึ่งครั้ง: การเชื่อมต่อที่ทำเครื่องหมายและไม่ทำเครื่องหมายควรไปคนละเส้นทาง และ ip rule show ควรแสดงลำดับความสำคัญที่คุณตั้งใจ หากทั้งสองโฟลว์ไปเส้นทางเดียวกัน เครื่องหมายไม่ได้ถูกใช้ในที่ที่คุณคิด