שאלו אפליקציית iOS אם הטלפון על VPN, והתשובה הכנה היא שהיא לא יכולה לדעת זאת במובן שאתם מתכוונים. ה-SDK לא חושף שום דגל של «המכשיר במנהרה», והממשקים הפרטיים שאולי היו מתקרבים לכך סגורים בפני אפליקציות שמפורסמות. אתם יכולים לצפות בתצורה של האפליקציה שלכם, במצב שתלוי בה, וברמז עקיף אחד או שניים ממחסנית הרשת. כל אחד מהם עונה על שאלה אחרת, ורוב הבדיקות השבורות נובעות מלקיחת אחד מהם כתשובה השלמה.

המיתוס של דגל VPN יחיד

האמונה היא שאי שם ב-SDK יש מאפיין שמדווח אם המכשיר במנהרה, כפי שדגל נגישות מדווח אם מארח עונה. מאפיין ציבורי כזה אינו קיים. וגם אם היה, «קיימת מנהרה» ו«התעבורה שלי משתמשת בה» הם טענות שונות, ורק השנייה חשובה לרוב האפליקציות.

הפער הזה הוא הסיבה לכך שספריות שמפרסמות גלאי VPN בשורה אחת נוטות לקרוא משהו שביר, כמו שם ממשק או מפתח פרוקסי, ולהציג אותו כפסק דין.

טענו את ההעדפות לפני שאתם סומכים על nil

מופע המנהל המשותף קיים ברגע שאתם מבקשים אותו, אבל מאפיין הפרוטוקול שלו נשאר nil עד שה-callback של הטעינה מסתיים. לכן פרוטוקול nil פירושו «עוד לא נטען» לפחות בתדירות שבה הוא פירושו «לא מותקן». בצעו את הקריאה בתוך בלוק ההשלמה, ורק אז החליטו: אובייקט פרוטוקול שקיים, עם דגל ההפעלה דלוק, הוא איך שנראה «מותקן».

אות שני יושב על אובייקט החיבור: המצב הפסול, שהמערכת מדווחת עליו כשאין לאפליקציה הזו תצורה מותקנת. מצב פסול יחד עם פרוטוקול nil אחרי טעינה שהושלמה הוא היעדרות אמיתית, לא מרוץ תזמון.

שינויי חיבור מגיעים כהתראות

מטפלים שמועברים ל-load ול-save מדווחים מה קרה לתצורה, לא מה המנהרה עושה. המתנה שאחד מהם יופעל בזמן החיבור היא מרוץ שלעולם אינו נפתר. עקבו במקום זאת אחר התראת שינוי המצב, וקראו את הערך הנוכחי של אובייקט החיבור כשהיא מגיעה.

לאחר שתצורה מותקנת, מצב החיבור עובר רצף קצר: מנותק, מתחבר, מחובר, מאשר מחדש, מתנתק. «מחובר» מתאר את המנהרה ולא את השרת שמאחוריה, ולכן אינו הוכחה שהתעבורה זורמת. On-demand יכול גם להעלות מנהרה כשהאפליקציה מושהית, ואז ההתראה מגיעה לפני שיש לכם מה לעדכן.

תמונת הפרוקסי המוגבלת היא רמז, לא פסק דין

CFNetwork יכול לתת לאפליקציה את הגדרות הפרוקסי הנוכחיות של המערכת, ובתוך התוצאה הזו יש מילון מוגבל עם מפתח לפי שם ממשק. שם שמתחיל ב-tun, utun, ppp, ipsec או tap הוא רמז לכך שיש מנהרה. זה נשאר תמונה של מה שהאפליקציה הזו יכולה לראות, לא הצהרה על היכן החבילות נוסעות.

ספקים חלוקים על השמות, ולכן קידומת חסרה אינה מוכיחה דבר, וממשק שקיים יכול להתקיים בלי לשאת תעבורה. נגישות חלשה עוד יותר: בקשה מוצלחת לכתובת פרטית מראה שהנתיב עבד עבור אותה בקשה באותו רגע, לא ש-VPN מותקן.

הסימולטור שואל את ה-Mac, ואפליקציות אחרות נשארות בלתי נראות

לסימולטור אין מחסנית רשת משלו; כל חיבור שהוא עושה הוא של ה-Mac. לכן VPN שרץ על ה-Mac המארח כבר בתוקף עבור האפליקציה המדומה, וההגדרות של הסימולטור עצמו לא מציגות דבר. אם המנהרה עלתה אחרי שהסימולטור התחיל, הפעלה מחדש שלו מהירה בדרך כלל מניפוי שגיאות באפליקציה. מארח בפורט לא סטנדרטי צריך את הפורט הזה בכתובת ה-URL, או העברה מקומית כמו socat TCP-LISTEN:12345,fork TCP:host:12345.

ממשקי API ציבוריים לא ימנו פרופילי VPN ששייכים לאפליקציות אחרות או לפרופילי תצורה. עבור אפליקציה ידועה אחת, בדיקת סכימת URL דרך canOpenURL היא הטריק הנייד, ומאז iOS 9 הסכימה הנשאלת חייבת להיות מוצהרת ב-Info.plist שלכם; אם תשמיטו אותה, הקריאה תחזיר false. OpenVPN Connect מגיב ל-openvpn://, מה שהופך אותו לדוגמה טובה ולגלאי כללי גרוע.

שלבו שלוש תצפיות ואמרו מה הן אומרות

בעבודה המעשית ערמו שלוש תוצאות: תצורה שנטענה ומופעלת, מצב חיבור שאינו פסול, ובקשה לכתובת שנגישה רק דרך המנהרה. כל אחת מהן מטעה לבדה; יחד הן אומרות מה האפליקציה יכולה לדעת ולא מה המשתמש מניח.

כתבו את התוצאה כשלוש שורות באבחון שלכם, לא כ-boolean אחד. כשמשתמש אומר שה-VPN כבוי בעוד האפליקציה שלכם חולקת, שלוש השורות מראות איזו תצפית סטתה, וזה ההבדל בין קריאת תמיכה שאפשר לפעול לפיה ובין כזו שמסתיימת ב«אצלי זה עובד».

מאמרים קשורים