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

ตำนาน: API คือโปรแกรมแก้ไขการตั้งค่า

มีความเชื่อว่าเพราะ iOS กำหนดค่าโปรไฟล์ IKEv1, IKEv2, L2TP และ IPsec ได้ แอปจึงสร้างโปรไฟล์ใดก็ได้เหล่านี้โดยทางโปรแกรม สร้างไม่ได้ เฟรมเวิร์กเปิดช่องการกำหนดค่าเพียงช่องเดียวให้แอปที่เรียกใช้ และช่องนั้นรับเฉพาะคลาสโปรโตคอลสาธารณะกลุ่มเล็ก ๆ เท่านั้น ทุกอย่างอื่นที่ผู้คนคาดหวัง ตั้งแต่ L2TP ไปจนถึงโปรไฟล์ที่ดาวน์โหลดมา อยู่นอกพื้นผิวนั้นหรือเป็นข้อมูลส่วนตัวของ Apple

ความล้มเหลวที่ตามมามักไม่ใช่บั๊ก แต่เป็น API ที่ปฏิเสธงานที่ไม่เคยได้รับมอบหมาย และวิธีแก้คือออกแบบหน้าจอตามสิ่งที่ API เป็นเจ้าของ

ออบเจ็กต์โปรโตคอลสามตัวและตัวที่ไม่มีอยู่

ตัวเลือกของคุณคือ IKEv1 ผ่าน NEVPNProtocolIPSec, IKEv2 ผ่าน NEVPNProtocolIKEv2 และ NETunnelProviderProtocol หากคุณจัดส่งส่วนขยายอุโมงค์แพ็กเก็ตของคุณเอง เอกสารอ้างอิง NEVPNManager แสดงรายการออบเจ็กต์โปรโตคอลที่ยอมรับ L2TP และ PPTP ไม่เคยปรากฏในรายการนั้นเพราะ Apple ไม่ได้เผยแพร่คลาสสำหรับทั้งสอง การลองอย่างใดอย่างหนึ่งจบลงเมื่อบันทึกด้วยข้อผิดพลาด หรือแย่กว่านั้น ด้วยการกำหนดค่าที่ระบบปฏิเสธที่จะใช้อย่างเงียบ ๆ

โค้ดเดสก์ท็อปเป็นไปตามกฎอื่น บน macOS SCNetworkInterfaceCreateWithInterface ซ้อนประเภทอินเทอร์เฟซเช่น L2TP บน IPv4 และแนบกับบริการเครือข่าย และ networksetup -connectpppoeservice เริ่มต้นผลลัพธ์ ต้องมีสิทธิ์ผู้ดูแลระบบและเครื่องมือช่วย เพราะความลับที่ใช้ร่วมกันและรหัสผ่านจะเข้าไปในพวงกุญแจของระบบ คัดลอกการออกแบบนั้นไปยัง iOS แล้วจะไม่มีอะไรคอมไพล์

ส่งการอ้างอิงพวงกุญแจ ไม่ใช่รหัสผ่าน

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

การตรวจสอบด้วยใบรับรองใช้เส้นทางอื่น: identityData บวก identityDataPassword สำหรับบล็อบ PKCS#12 การจัดส่งบล็อบนั้นภายในบันเดิลแอปเป็นนิสัยที่สืบทอดมาจากโค้ดตัวอย่าง ไม่ใช่การตัดสินใจเปิดตัว เพราะรหัสผ่านเดินทางไปกับมันและทุกสำเนาของแอปมีตัวตนเดียวกัน

สิทธิและการพร้อมใช้งานเป็นประตูของทุกสิ่ง

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

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

โหลด แก้ไข บันทึก แล้วสังเกตลำดับตามคำขอ

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

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

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

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