ٹنل اوپر آتا ہے، چابی کا نشان ظاہر ہوتا ہے، مگر براؤزر کی ہر درخواست اب بھی وقت ختم ہو کر ناکام ہوتی ہے۔ 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 سے کنکشن ری سیٹ کا مطلب ہے کہ دور کا سرا بند ہو گیا جبکہ آپ کا کوڈ ابھی پڑھ رہا تھا۔ غلط پتے کی خرابی ہیڈر پارسنگ یا آفسیٹ بگ کی طرف اشارہ کرتی ہے، نیٹ ورک کی طرف نہیں۔

کام کی ترتیب: بلاکنگ موڈ آن، فی پڑھائی ایک پیکٹ، ہیڈر پارس، ساکٹ محفوظ، پے لوڈ بھیجا گیا، حوالگی پر صاف بندش اور منزل ڈھانپنے والی روٹ فہرست۔

متعلقہ مضامین