ทันเนล VPN ซ้อนกัน: ทำไมชั้นในจึงหยุดกับแพ็กเก็ตใหญ่
ทันเนลแต่ละอันใช้งบแพ็กเก็ตของเส้นทางไปบางส่วนก่อนที่อันถัดไปจะเริ่ม รวมเฮดเดอร์เข้าด้วยกันแล้วเซสชันชั้นในจะล้มเหลวกับแพ็กเก็ตใหญ่
DNS แก้ได้แล้ว เซสชัน SSH ยังอยู่ แต่พออัปโหลดไฟล์ใหญ่กลับค้าง ขณะที่ ping ไปยังโฮสต์เดิมยังตอบสนอง การแยกกันแบบนี้ชี้ไปที่ขนาดแพ็กเก็ต ไม่ใช่ทันเนลที่เสีย ทันเนลซ้อนกันไปถึงจุดนั้นที่ขนาดที่ไม่มีทันเนลใดอันเดียวจะไปถึง ทันเนลชั้นในยังปกติดี มันเพียงได้รับแพ็กเก็ตที่ไม่พอดีอีกต่อไป
MTU ของเส้นทางหายไปไหนจริง ๆ
การห่อหุ้มแต่ละชั้นใช้ไบต์ก่อนที่ชั้นถัดไปจะได้คิว เส้นทาง Ethernet ให้ 1500 ไบต์แก่แพ็กเก็ตชั้นนอก และทันเนลชั้นนอกก็ใช้ส่วนของตนก่อนที่อะไรข้างในจะถูกกำหนดที่อยู่ได้ ค่าโอเวอร์เฮดที่เดาไว้หนึ่งค่าจะผิดไปเท่ากับจำนวนที่สำคัญพอดี
เรียงชั้นตามลำดับ: เส้นทางเข้าถึง การขนส่งชั้นนอก ทันเนลชั้นนอก การขนส่งชั้นใน ทันเนลชั้นใน แอปพลิเคชัน นับเฮดเดอร์แต่ละอันหนึ่งครั้ง และแยก UDP ออกจากเฮดเดอร์กับแท็กของทันเนลเอง
สองชั้น WireGuard นับครั้งเดียว
ยกเส้นทางเข้าถึง IPv4 ที่มีทันเนล WireGuard หนึ่งอันซ้อนอยู่ในอีกอัน ชั้นนอกใช้ 20 ไบต์ IPv4, 8 ไบต์ UDP และ 32 ไบต์สำหรับเฮดเดอร์ข้อมูล WireGuard พร้อมแท็กยืนยันตัวตน ข้างในนั้นทันเนลชั้นในต้องการเฮดเดอร์ IPv4 20 ไบต์และเฮดเดอร์ UDP 8 ไบต์ของตัวเองก่อนโอเวอร์เฮด WireGuard 32 ไบต์ชุดที่สอง ส่วนที่เหลือบรรจุเฮดเดอร์ IPv4 เฮดเดอร์ TCP และข้อมูล เส้นทางชั้นนอกแบบ IPv6 ใช้ 40 แทน 20 และเหลือ 1320
| Layer | Bytes |
|---|---|
| Path MTU | 1500 |
| Outer IPv4 header | 20 |
| Outer UDP header | 8 |
| Outer WireGuard header and tag | 32 |
| Inner transport IPv4 header | 20 |
| Inner UDP header | 8 |
| Inner WireGuard header and tag | 32 |
| Innermost IPv4 header | 20 |
| TCP header | 20 |
| Payload that fits | 1340 |
ผลคำนวณลงเอยที่ 1340 ไบต์ หนึ่งชั้นภายใต้กฎเดียวกันเหลือ 1400 สำหรับเพย์โหลด TCP นั่นคือ 1500 ลบ 20, 8, 32, 20 และ 20 และส่วนต่าง 60 ไบต์ก็คือการห่อหุ้มชั้นในที่ทันเนลที่สองเพิ่มเข้ามาพอดี
นำ 1400 ไปใช้กับเส้นทางซ้อนกัน แล้วทันเนลชั้นในจะขาดไป 60 ไบต์ มองไม่เห็นจนกว่าแพ็กเก็ตจะใหญ่พอที่ต้องการมัน การเติมเต็มและตัวเลือกการแบ่งส่วนของโปรโตคอลเองก็ขยับตัวเลขอีกครั้ง ดังนั้นจงเชื่อตาราง
MTU, MSS และการแบ่งส่วนทำงานคนละที่
MTU ของอินเทอร์เฟซจำกัดสิ่งที่อินเทอร์เฟซจะส่งออก ส่วนการบีบ MSS ใน TCP เปลี่ยนสิ่งที่คู่ TCP ยินดีจะส่ง การบีบช่วยแก้เซสชัน TCP และไม่ทำอะไรให้ดาตาแกรม UDP ขนาดใหญ่ นี่คือวิธีที่การแก้ปัญหาดูสำเร็จกับแอปหนึ่งและพลาดอีกแอปอย่างเงียบ ๆ ตัวเลือกการแบ่งส่วนของโปรโตคอลเองคือคันโยกที่สามพร้อมความล้มเหลวของมันเอง MTU ของอินเทอร์เฟซคือก้าวแรกที่พบได้บ่อยและหยาบที่สุด
ทันเนลแบบบริดจ์และแบบเราเตอร์บรรทุกเฟรมต่างกัน ตัวเลขจากการติดตั้งอื่นจึงแทบไม่ถ่ายโอน การค้นหา MTU ของเส้นทาง ซึ่งอธิบายไว้ใน RFC 8201ช่วยได้เพียงตราบเท่าที่ข้อความ ICMP ที่มันพึ่งพาอยู่ถูกปล่อยให้ผ่าน
หาชั้นที่ขาดไป
ตรวจสอบแต่ละทันเนลแยกกันก่อนจะซ้อนกัน หากข้อกำหนดอนุญาตให้เปรียบเทียบ โพรบขนาดคงที่ตัดสินเรื่องนี้: ping -M do -s 1472 -c 3 10.8.0.1 ส่งแพ็กเก็ต IPv4 ขนาด 1500 ไบต์เต็ม ๆ ภายในชั้นนั้น เพิ่มชั้นที่สองแล้วทำโพรบเดิมซ้ำ เพื่อให้ความล้มเหลวใด ๆ อยู่ในความเปลี่ยนแปลงที่รู้จัก
เมื่อการถ่ายโอนหยุด ให้เปลี่ยนพารามิเตอร์ที่บันทึกไว้ทีละตัวและบันทึกขนาดที่ล้มเหลว ตรวจเส้นทางขากลับด้วย เพราะการเรียกซ้ำของเส้นทางแบบซ้อนกันสามารถเลียนแบบปัญหาขนาดแพ็กเก็ตได้ใกล้พอที่จะทำให้เสียเวลาทั้งบ่าย การตอบกลับ ICMP ที่ถูกกรองอาจซ่อนขีดจำกัดจริง โพรบจึงสำคัญกว่าการให้เหตุผล
เขียนงบประมาณไว้ตรงที่คนถัดไปจะหาเจอ
ตารางที่มีหนึ่งแถวต่อชั้นอยู่ได้นานกว่ากฎง่าย ๆ เก็บไว้ข้างแผนภาพทันเนล เพื่อไม่ให้ใครคำนวณซ้ำภายใต้แรงกดดัน
ทันเนลมากขึ้นหมายถึงการพึ่งพามากขึ้น แผนย้อนกลับจึงคู่ควรกับตำแหน่งข้างงบประมาณ หากตัวเลขยังไม่ลงตัว ให้วัดเส้นทางแทนการเดาอีกครั้ง เป้าหมายคือตัวเลขที่คุณปกป้องได้ ไม่ใช่ตัวเลขที่จำได้