टनेल सुरू होते, कीचे चिन्ह दिसते, आणि ब्राउझरमधील प्रत्येक विनंती अजूनही वेळ संपून अपयशी होते. 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 कडून जोडणी रीसेट म्हणजे तुमचा कोड अजून वाचत असताना दूरचे टोक बंद झाले. चुकीच्या पत्त्याची त्रुटी हेडर पार्सिंग किंवा ऑफसेट बगकडे निर्देश करते, नेटवर्ककडे नाही.

कामाचा क्रम: ब्लॉकिंग मोड सुरू, प्रति वाचन एक पॅकेट, हेडर पार्स झाले, सॉकेट संरक्षित, पेलोड पाठवले, हस्तांतरणावेळी स्वच्छ बंद, आणि गंतव्य व्यापणारी रूट यादी.

संबंधित लेख