รหัสข้อผิดพลาดสองตัวอธิบายความพยายามครั้งแรกส่วนใหญ่ของ VPN แบบ Network Extension บน iOS ได้แก่ NEVPNErrorDomain Code=4 และ Code=5 ทั้งสองไม่ใช่คำร้องเรียนจากเซิร์ฟเวอร์ ตัวหนึ่งปรากฏเมื่อแอปเขียนการตั้งค่าลงในออบเจ็กต์ที่ไม่เคยถูกอ่านจากดิสก์ อีกตัวปรากฏเมื่อการเขียนเองล้มเหลว ซึ่งมักเกิดจากการบันทึกโปรไฟล์ในขณะที่ยังปิดใช้งานอยู่ ทั้งสองแก้ได้ด้วยการเปลี่ยนลำดับการเรียกสี่ครั้ง ไม่ใช่การแตะพารามิเตอร์ IKEv2

โหลดก่อน ไม่อย่างนั้นการบันทึกก็ไม่มีอะไรให้เปรียบเทียบ

ตัวจัดการเก็บสำเนาของโปรไฟล์ที่บันทึกไว้ และออบเจ็กต์ที่คุณแก้ไขไม่ใช่สำเนานั้นจนกว่าคุณจะอ่านมัน เรียก loadFromPreferences ก่อน แก้ไขภายในตัวจัดการเสร็จสิ้น แล้วจึงบันทึก ถ้าข้ามการอ่าน เฟรมเวิร์กจะเห็นความไม่ตรงกันระหว่างสิ่งที่มันมีกับสิ่งที่คุณเขียน ใน Swift รูปแบบเหมือนกันทุกขั้นตอน และแต่ละขั้นตอนอยู่ในคลอเชอร์ของตัวเอง:

let mgr = NEVPNManager.shared()
mgr.loadFromPreferences { loadErr in
    guard loadErr == nil else { return }
    let proto = NEVPNProtocolIKEv2()
    proto.serverAddress = "vpn.example.net"
    proto.username = "alice"
    proto.useExtendedAuthentication = true
    mgr.protocolConfiguration = proto
    mgr.isEnabled = true
    mgr.saveToPreferences { saveErr in
        // do not start here; reload, then connect
    }
}

การเริ่มทันเนลจากภายในคลอเชอร์บันทึกเป็นความผิดเดียวกันในอีกที่หนึ่ง มันทำงานก่อนที่โปรไฟล์จะถูกอ่านใหม่ ดังนั้นการเรียกเริ่มจึงเห็นสถานะที่คุณสร้าง ไม่ใช่สถานะที่ถูกบันทึก คลอเชอร์บันทึกจบด้วย loadFromPreferences ครั้งที่สอง และมีเพียงตัวจัดการเสร็จสิ้นนั้นที่เรียก startVPNTunnel

แฟล็กเปิดใช้งานเป็นส่วนหนึ่งของการบันทึก

โปรไฟล์ที่บันทึกไว้จะไม่ทำงานจนกว่าจะเปิด isEnabled = true ในการเขียนเดียวกัน มิฉะนั้นโปรไฟล์จะลงดิสก์ในสถานะปิดใช้งาน และ startVPNTunnel จะปฏิเสธแม้การตั้งค่าจะแสดงการกำหนดค่าที่ดูสมบูรณ์

การแก้ไขจากภายนอกเป็นอีกครึ่งหนึ่ง ถ้าผู้ใช้เปลี่ยนบางอย่างในการตั้งค่า หรืออุปกรณ์ย้ายระหว่างเครือข่าย ให้อ่านใหม่ก่อนเชื่อค่าที่คุณยังถืออยู่ในหน่วยความจำ ออบเจ็กต์ไม่ได้เฝ้าดูการเปลี่ยนแปลงเหล่านั้นให้คุณ สำเนาที่เก่าคือวิธีที่แอปเขียนโปรไฟล์ซึ่งย้อนการแก้ไขของผู้ใช้อย่างเงียบ ๆ ฟิลด์สองตัวที่อยู่ติดกันสร้างปัญหาเงียบในขณะเดียวกัน: กฎ on-demand ต้องเป็นอาร์เรย์ของออบเจ็กต์กฎ ไม่ใช่ตัวยึดตำแหน่งว่าง และ disconnectOnSleep ควรสะท้อนพฤติกรรมที่คุณเลือก ไม่ใช่ค่าเริ่มต้นที่คัดลอกมา

มีเพียงสองโปรโตคอลที่ใช้ได้สำหรับแอปของบุคคลที่สาม

Network Extension ให้ IPsec และ IKEv2 กับแอป L2TP และ PPTP อยู่ภายในระบบ ดังนั้นแอปที่ต้องการจึงไม่ได้ และคำตอบที่เป็นจริงคือเกตเวย์ที่รองรับ IKEv2 หรือโปรไฟล์การกำหนดค่าที่จัดการ

ข้อมูลรับรองเป็นไปตามรูปแบบเดียวกัน ใส่รหัสผ่านใน Keychain และส่งข้อมูลอ้างอิงถาวรแทนสตริง การอ้างอิงที่เป็นศูนย์ตอนบันทึกมักหมายความว่าการค้นหาเกิดขึ้นก่อนรายการจะถูกเขียน ไม่ใช่ตัวจัดการเสีย

ทั้งสองเป็นการตัดสินใจออกแบบ ไม่ใช่วิธีเลี่ยง แอปที่เก็บรหัสผ่านไว้ในการตั้งค่าของตัวเองเลือกเส้นทางที่เฟรมเวิร์กไม่แนะนำ และความล้มเหลวที่เกิดขึ้นอ่านได้เหมือนข้อผิดพลาดในการบันทึก

ตัดสิทธิ์ออกก่อนเขียนโค้ดใหม่

เมื่อ loadFromPreferences ไม่เรียกกลับเลย สาเหตุที่เป็นไปได้คือความสามารถ Network Extension ที่ขาดหาย หรือโปรไฟล์การจัดเตรียมที่ไม่มีความสามารถนั้น ความล้มเหลวนั้นค้างแทนที่จะให้ข้อผิดพลาด จึงมีการเขียนโค้ดที่ทำงานได้ใหม่หลายชั่วโมง ตรวจสอบสิทธิ์บนบิลด์ที่ลงนามซึ่งคุณตั้งใจจะส่ง เพราะการรันในซิมูเลเตอร์และการรันบนอุปกรณ์อาจต่างกัน และเป้าหมายที่สำคัญคืออุปกรณ์ เปิดการตั้งค่าการลงนามของเป้าหมายและยืนยันว่าความสามารถ Network Extension มีอยู่สำหรับบิลด์นั้นโดยเฉพาะ

โปรไฟล์การจัดเตรียมที่ไม่มีสิทธิ์ล้มเหลวแบบเดียวกันบนฮาร์ดแวร์ ขณะที่บิลด์เดียวกันอาจโหลดได้ปกติในซิมูเลเตอร์ ทดสอบไฟล์เก็บถาวรที่ลงนามบนอุปกรณ์จริงก่อนเขียนลำดับการเรียกใหม่

ดูการเปลี่ยนแปลงสถานะ ไม่ใช่สมมติฐาน

เฝ้าดู NEVPNStatusDidChangeNotification และบันทึก manager.connection.status หลังจากทุกขั้นตอน สถานะที่ไม่เคยออกจาก invalid หมายความว่าโปรไฟล์ไม่ได้ถูกบันทึกหรือไม่มีสิทธิ์ การเชื่อมต่อที่ไปถึง connecting และไม่เคยเชื่อมต่อชี้ไปที่ข้อเสนอหรือข้อมูลรับรอง ซึ่งเป็นการสอบสวนอื่นด้วยหลักฐานอื่น

ยืนยันว่าโปรไฟล์ปรากฏใต้การตั้งค่า ทั่วไป VPN และบันทึกข้อผิดพลาดจากทุกคลอเชอร์ ข้อเท็จจริงสองข้อนี้แยกบั๊กลำดับออกจากบั๊กสิทธิ์โดยไม่ต้องเดา

บทความที่เกี่ยวข้อง