टनेल माथि आउँछ, कुञ्जीको प्रतिमा देखिन्छ, तर ब्राउजरको हरेक अनुरोध अझै समय सकिएर असफल हुन्छ। VpnService एपमा यो संयोजन सामान्यतया पढ्ने लूप जिवित छ र आउटपुट आधा बिग्रिएको छ भन्ने अर्थ हुन्छ, सर्भरले ह्यान्डशेक अस्वीकार गर्यो भन्ने होइन। Android ले पहिले नै इन्टरफेस बनाइसक्यो, एपको ट्राफिक त्यसमा सार्यो र तपाईंको प्रक्रियालाई फाइल डिस्क्रिप्टर दियो। त्यो डिस्क्रिप्टरपछिको सबै कुरा तपाईंको कोड हो, र एउटा छुटेको कलले पूरै स्ट्रिम निल्न पर्याप्त छ।

प्रणालीले के दिन्छ र के दिँदैन

establish() ले tun इन्टरफेसका लागि ParcelFileDescriptor फर्काउँछ। प्रणालीले बाहिर जाने IP प्याकेट त्यसमा लेख्छ र तपाईंको प्रक्रियाले ती पढ्ने, कहाँ जाने निर्णय गर्ने र साधारण सकेटमार्फत पठाउने अपेक्षा गर्छ। तल कर्नेल फर्वार्डिङ छैन, त्यसैले कोही नपढ्दा प्याकेट छाडिन्छन् र इन्टरफेसका काउन्टर कहिल्यै सर्दैनन्।

अनुमानको सट्टा गणनाबाट सुरु गर्नुहोस्। हरेक सफल पढाइमा काउन्टर बढाउनुहोस् र पहिलो केही प्याकेटको गन्तव्य र प्रोटोकल लग गर्नुहोस्। ट्राफिक उत्पन्न हुँदा काउन्टर शून्य रह्यो भने त्रुटि तपाईंको फर्वार्डिङ कोडभन्दा माथि छ, जसले खोजलाई builder कन्फिगरेसन र पढ्ने मोडमा सीमित गर्छ। काउन्टर सर्छ तर ब्राउजर अझै असफल हुन्छ भने त्रुटि पठाउने वा फर्कने बाटोमा छ।

ब्लकिङ पढाइले लूप सर्छ कि सर्दैन भन्ने तय गर्छ

setBlocking(true) ले डिस्क्रिप्टरलाई ब्लकिङ मोडमा राख्छ र API 21 देखि छ। पुराना संस्करणमा उपाय सानो JNI सहायक हो, जसले काँचो डिस्क्रिप्टरमा fcntl प्रयोग गरी O_NONBLOCK हटाउँछ। मोड महत्त्वपूर्ण छ किनभने पर्खिरहेको प्याकेट नभएको पढाइले के गर्न पाउँछ भन्ने यसैले तय गर्छ।

नन-ब्लकिङ मोडमा त्यो पढाइ तुरुन्तै ऋणात्मक मानसँग फर्किन्छ, र नतिजा बेवास्ता गर्ने लूप कुनै ट्राफिक नसारी कोर घुमाउँछ। ब्लकिङ मोडमा पढाइ पर्खन्छ, फर्वार्डिङ थ्रेडलाई त्यही चाहिन्छ, तर त्यसपछि थ्रेड रोक्न सकिँदैन। पढाइ असफल बनाउने समर्थित तरिका डिस्क्रिप्टर बन्द गर्नु हो, ताकि लूप बाहिर निस्कन सकोस्। प्रक्रिया मार्ने वा थ्रेड रोक्ने गर्दा अर्को सुरुवातले इन्टरफेससँग नमिल्ने डिस्क्रिप्टर बोक्न सक्छ।

हरेक कलमा इन्टरफेसको MTU आकारको बफरमा एउटा प्याकेट पढ्नुहोस्, र शून्य वा ऋणात्मक फिर्तीलाई खाली प्याकेट होइन, त्रुटि मान्नुहोस्।

पहिलो पठाउने अघि protect(), पछि होइन

इन्क्याप्सुलेटेड प्याकेट बोक्ने हरेक सकेट पहिले सुरक्षित गर्नुपर्छ। असुरक्षित सकेटले तपाईंले भर्खरै राखेका तीही रुटिङ नियम पालना गर्छ, त्यसैले त्यसका प्याकेट टनेलमा फर्किन्छन् र तपाईंको आफ्नै पढ्ने लूपले तिनलाई फेरि उठाउँछ। त्यसपछि टनेलले आफ्नै आउटपुट अनन्त रूपमा फर्वार्ड गर्छ, र बाहिरबाट यो खुल्ने तर कहिल्यै जवाफ नदिने जडानजस्तो देखिन्छ।

क्रम protect, त्यसपछि connect वा bind, त्यसपछि send हो। connect पछि protect बोलाउँदा अघिल्लो रुट निर्णय रहन सक्छ, त्यसैले कलले true फर्काए पनि सकेटले गलत बाटो प्रयोग गरिरहन्छ। फर्काइने बुलियन जाँच्नुहोस् र false हुँदा ठूलो स्वरमा असफल हुनुहोस्, काम गर्न नसक्ने send मा प्रवेश गर्नुको सट्टा।

protect() कहिल्यै नछोएको सकेटमा sendto बाट आउने अनुमति त्रुटि यो गल्तीको सामान्य चिन्ह हो।

UDP नमुनाले HTTPS बोक्दैन

अधिकांश ट्युटोरियलले प्रतिलिपि गर्ने फर्वार्डिङ नमुनाले UDP मात्र ह्यान्डल गर्छ। TCP लाई ह्यान्डशेक, क्रम संख्या, स्वीकृति र पुनःपठाउने चाहिन्छ, र tun डिस्क्रिप्टर र सकेटबीच पेलोड प्रतिलिपि गर्ने लूपले तीमध्ये केही पनि दिँदैन। त्यसैले UDP DNS प्रश्न पास हुन सक्छ तर हरेक HTTPS अनुरोध अड्किन्छ। या त प्रयोगकर्ता स्पेसमा TCP स्ट्याक चलाउनुहोस् या यन्त्रैमा TCP अन्त्य गरी स्ट्रिम फर्वार्ड गर्ने स्थानीय प्रोक्सीलाई जडान दिनुहोस्।

केही पनि पुनःलेख्नु अघि विभाजन परीक्षण गर्नुहोस्: एउटा UDP प्रश्न पठाउनुहोस् र त्यही होस्टमा एउटा TCP जडान खोल्नुहोस्। UDP बाटो चल्यो र TCP बाटो पहिलो SYN मा अड्कियो भने समस्या फर्वार्डिङ कोडमा छ, सर्भरमा होइन। त्यो एउटा तुलनाले उपयोगी केही नभएका सर्भर लग पढ्नमा खर्च हुने धेरै समय बचाउँछ।

रुट सूची र प्रति-एप फिल्टरले देखिने कुरा सीमित गर्छन्

addAddress, addRoute र addDns ले प्रणालीले टनेलमा के पठाउने तय गर्छन्। रुट सूचीबाहिरको गन्तव्य कहिल्यै तपाईंको डिस्क्रिप्टरमा पुग्दैन, त्यसैले जति फर्वार्डिङ तर्क थपे पनि त्यो सुधारिँदैन। तपाईंले गर्ने builder कल लग गर्नुहोस् र एपले साँच्चै पुग्न खोज्ने ठेगानासँग तुलना गर्नुहोस्।

प्रति-एप छनोटको आफ्नै तल्लो सीमा छ: addAllowedApplication र addDisallowedApplication लाई API 21 चाहिन्छ, र पुराना संस्करणमा ती विधि नै छैनन्। प्याकेटअनुसार फिल्टर गर्ने डिजाइन त्यहाँ चल्नै सक्दैन।

पुनःस्थापनाले पुराना डिस्क्रिप्टर छाड्छ

establish() फेरि बोलाउँदा नयाँ डिस्क्रिप्टर आउँछ र अघिल्लो इन्टरफेस बन्द हुन्छ। पुरानो डिस्क्रिप्टर अब अवैध छ, त्यसैले त्यसमा अझै ब्लक भएको थ्रेडलाई त्रुटि आउँछ, र पुरानो बाटोका लागि बनाइएका सकेट बदल्नुपर्न सक्छ। onRevoke प्रयोगकर्ता वा प्रणालीले खोसेको टनेलका लागि कलब्याक हो। पुनःस्थापनाअघि पाठक रोक्ने गरी जीवनचक्र एउटै मालिकसँग राख्दा जोडिएको-तर-मृत अवस्था धेरै टर्छ।

हरेक त्रुटि उसको चरणअनुसार पढ्नुहोस्। recvfrom बाट जडान रिसेट भन्नाले तपाईंको कोड अझै पढिरहेका बेला टाढाको छेउ बन्द भयो भन्ने हो। खराब ठेगानाको त्रुटि हेडर पार्सिङ वा अफसेट बगतिर संकेत गर्छ, नेटवर्कतिर होइन।

कामको क्रम: ब्लकिङ मोड खुला, प्रति पढाइ एउटा प्याकेट, हेडर पार्स भएको, सकेट सुरक्षित, पेलोड पठाइएको, हस्तान्तरणमा सफा बन्द, र गन्तव्य ढाक्ने रुट सूची।

सम्बन्धित लेखहरू