iOS VPN ऐप टनल चालू होने पर भी डिस्कनेक्टेड क्यों दिखाता है
आपका iOS ऐप टनल को नियंत्रित करता है पर उसका मालिक नहीं है, और मैनेजर की स्थिति कैश में है। पहले प्राथमिकताएँ लोड करें, फिर स्थिति और इंटरफ़ेस काउंटर पढ़ें।
आपका ऐप कहता है डिस्कनेक्टेड, मेन्यू बार कहता है कनेक्टेड, और ट्रैफ़िक स्पष्ट रूप से बह रहा है। यह अंतर कोई रेस कंडीशन नहीं है जिसे दोबारा कोशिश से ठीक किया जा सके: ऐप और टनल अलग-अलग प्रक्रियाएँ हैं, और आपका कोड जो ऑब्जेक्ट पढ़ता है वह सिस्टम द्वारा संग्रहीत कॉन्फ़िगरेशन का कैश किया हुआ दृश्य है। Apple की Personal VPN सतह एक कंट्रोल API है, डेटा पथ नहीं, और उसका अधिकांश अजीब व्यवहार इसी एक तथ्य से निकलता है। हर कॉल के नीचे वास्तव में क्या होता है, यह रहा।
मैनेजर ऑब्जेक्ट कैश किया हुआ दृश्य है, टनल नहीं
NETunnelProviderManager सिस्टम के स्वामित्व वाले प्राथमिकता स्टोर से भरा जाता है, इसलिए loadFromPreferences पूरा होने तक उसके गुण कुछ भी मायने नहीं रखते। उससे पहले connection.status पढ़ेंगे तो आपको डिफ़ॉल्ट मान मिलेगा, और इसीलिए रीलॉन्च के बाद पहला स्थिति रीफ़्रेश टनल चालू होने पर भी डिस्कनेक्टेड बताता है। पहले लोड करें, फिर उसी कम्प्लीशन हैंडलर से स्थिति और प्रोटोकॉल कॉन्फ़िगरेशन पढ़ें। पोलिंग के बजाय बाद के बदलाव NEVPNStatusDidChange से देखें, और ध्यान दें कि सूचना On Demand द्वारा शुरू किए गए कनेक्शन के लिए भी आती है, जहाँ कुछ भी लौटाने के लिए कोई ऐप कॉल ही नहीं होता। प्रोटोकॉल सेटिंग्स पर भी यही लागू होता है: वे लोड किए गए कॉन्फ़िगरेशन से पढ़ी जाती हैं, ऐप द्वारा भेजे गए से नहीं।
टनल स्वयं Network Extension प्रदाता प्रक्रिया में रहता है, इसलिए ऐप कनेक्शन खोए बिना अपनी स्थिति खो सकता है। इंटरफ़ेस जो कुछ दिखाता है वह मैनेजर से फिर से बनाया जाना चाहिए, पिछले सत्र से याद नहीं रखा जाना चाहिए।
शुरू करने का क्रम: सहेजें, लोड करें, फिर शुरू करें
प्रदाता-आधारित कनेक्शन को क्रम में तीन चरण चाहिए। प्रदाता कॉन्फ़िगरेशन लिखें और saveToPreferences कॉल करें, मैनेजर लोड करें ताकि सहेजा गया कॉन्फ़िगरेशन वही हो जो आपके पास है, फिर NETunnelProviderSession.startVPNTunnel() से शुरू करें। सहेजना छोड़ दें तो शुरू करने के पास शुरू करने को कुछ नहीं है; सहेजने से पहले लोड करें तो मैनेजर अब भी पुराना कॉन्फ़िगरेशन दर्शाता है।
startVPNTunnel जो बूलियन लौटाता है वह केवल कहता है कि अनुरोध स्वीकार हुआ। प्रदाता-स्तर की विफलताएँ बाद में डिस्कनेक्टेड स्थिति में बदलाव के रूप में आती हैं, जिसे आप NEVPNStatusDidChange सूचना से देखते हैं, और सूचना हैंडलर को loadFromPreferences के बाद connection.status फिर से पढ़ना होता है क्योंकि कैश किया हुआ मान अब भी पुराना हो सकता है। अनुरोध-स्तर की विफलताएँ कॉल के अपवाद फेंकने वाले रूप से तुरंत लौटती हैं, या startVPNTunnelAndReturnError: के त्रुटि आउट-पैरामीटर से। जो कोड लौटाए गए मान को परिणाम मानता है वह ऐसे कनेक्शन की सूचना देता है जो कभी स्थापित ही नहीं हुआ। दूसरी खामोश विफलता ऐसा प्रदाता बंडल पहचानकर्ता है जो स्थापित एक्सटेंशन से मेल नहीं खाता: अनुरोध अस्वीकार हो जाता है, और संदेश में कुछ भी पहचानकर्ता की ओर संकेत नहीं करता। पहचानकर्ता गलत हो तो अनुरोध सामान्यतः तुरंत विफल हो जाता है, प्रदाता की कोई लॉग पंक्ति आने से पहले ही।
शुरू करने के बाद प्राथमिकताएँ फिर से लोड करना ही स्थिति स्क्रीन को सही बनाता है। सिस्टम कॉन्फ़िगरेशन बदले तो मैनेजर आपको नया कॉन्फ़िगरेशन धकेलता नहीं है।
ट्रस्ट सामग्री प्रोफ़ाइल से आती है, ऐप कोड से कभी नहीं
iOS ट्रस्ट स्टोर में रूट प्रमाणपत्र जोड़ने का कोई समर्थित तरीका ऐप के पास नहीं है, इसलिए Personal VPN कॉन्फ़िगरेशन केवल उस सामग्री का संदर्भ दे सकता है जिस पर डिवाइस पहले से भरोसा करता है: स्थापित प्रोफ़ाइल, डिवाइस प्रबंधन, या किसी CA द्वारा स्थापित श्रृंखला जिस पर सिस्टम अन्य कारणों से भरोसा करता है। जो ऐप पहली बार चलने पर अपना CA बनाता है और अपेक्षा करता है कि सिस्टम उसे मानेगा, वह प्रदाता के भीतर सत्यापन में विफल होगा, जहाँ ऐप का इंटरफ़ेस कारण नहीं देख सकता।
उस सीमा को वैसा ही डिज़ाइन बाधा मानें जैसी वह है और नामांकन प्रोफ़ाइल के साथ ट्रस्ट एंकर भेजें। VPN प्रमाणीकरण को ट्रस्ट निर्णय से अलग रखें, क्योंकि वे अलग-अलग जगह विफल होते हैं और अलग-अलग लोग उन्हें डिबग करते हैं।
काउंटर इंटरफ़ेस से आते हैं, VPN API से नहीं
मैनेजर स्थिति और कॉन्फ़िगरेशन दिखाता है, और प्रति टनल बाइट गिनने वाला कुछ नहीं। अगर आपको उपयोग के आँकड़े चाहिए, तो getifaddrs() कॉल करें और संबंधित इंटरफ़ेस के लिए if_data पढ़ें: Wi-Fi के लिए en0, सेलुलर के लिए pdp_ip इंटरफ़ेस, और टनल के लिए ही utun डिवाइस। utun काउंटर आंतरिक ट्रैफ़िक का वर्णन करते हैं और प्रोटोकॉल ओवरहेड शामिल करते हैं।
ये आँकड़े अनुमान हैं, प्रति ऐप लेखा नहीं, और इंटरफ़ेस फिर से बनने पर वे रीसेट हो जाते हैं। इंटरफ़ेस में उन्हें इसी तरह लेबल करें, वरना कोई उन्हें ग्राहक को बिल करने के लिए उपयोग करेगा। अगर आपको प्रति ऐप आँकड़े चाहिए, तो आपको बिल्कुल अलग तंत्र चाहिए, इन फ़ील्ड्स का बेहतर पठन नहीं।
सफ़ाई stopVPNTunnel में है, समाप्ति में नहीं
applicationWillTerminate आपको कुछ सेकंड देता है इससे पहले कि सिस्टम प्रक्रिया को मार सके, जो कनेक्शन तोड़ने के लिए भरोसेमंद जगह नहीं है। स्टॉप stopVPNTunnel() को भेजें या प्रदाता के स्टॉप कॉलबैक में संभालें, और जिस मैनेजर या कॉन्फ़िगरेशन पहचानकर्ता से आपने शुरू किया था उसे रखें ताकि स्टॉप डिवाइस के हर कॉन्फ़िगरेशन के बजाय उसी कनेक्शन को लक्षित करे।
उस पहचानकर्ता को उस प्रोफ़ाइल के साथ संग्रहीत करें जिसका वह है, क्योंकि मैनेजर ऑब्जेक्ट यह दर्ज नहीं करता कि उपयोगकर्ता ने कौन-सा कॉन्फ़िगरेशन चुना। और याद रखें कि On Demand जो कनेक्शन उठाता है उसके पीछे कोई ऐप कॉल ही नहीं होता, इसलिए स्थिति स्क्रीन को कुछ भी खींचने से पहले अब भी प्राथमिकताएँ लोड करनी होती हैं।