VpnService protect() নাকি অ্যাপ বাদ: রাউটিং ঠিক করে কোনটি
টানেল বহনকারী সকেটটি সুরক্ষিত করুন, নাকি পুরো অ্যাপটি বাদ দিন: যে তিনটি শর্ত ঠিক করে আপনার Android VPN-এর কতটা পরিসর দরকার।
টানেলের নিজস্ব প্যাকেট টানেলের বাইরে রাখার দুটি উপায় আছে: ট্রান্সপোর্ট সকেটটি সুরক্ষিত করা, অথবা পুরো অ্যাপটিকে VPN থেকে বের করে দেওয়া। এরা ভিন্ন সমস্যার সমাধান করে, আর সহজে সংযুক্ত করা যায় বলে বড়টিকে বেছে নেওয়াই সেই পথ যেখানে অ্যাপগুলো না বুঝেই লোকাল নেটওয়ার্ক অ্যাক্সেস ও বিভক্ত DNS হারায়। টানেলের বাইরে কী থাকতে হবে তা দিয়ে শুরু করুন, তারপর এমন ক্ষুদ্রতম পরিসর বেছে নিন যা তা অর্জন করে।
protect() টানেল থেকে কী সরায়
VpnService.protect() হলো প্রতি-সকেট কল। টানেল বহনকারী সকেট বা ডেসক্রিপ্টর আপনি এতে দেন, আর Android সেই সকেটটি চিহ্নিত করে যাতে এর ট্রাফিক VPN ইন্টারফেসের বদলে অন্তর্নিহিত নেটওয়ার্ক ব্যবহার করে। অ্যাপ যে বাকি সব পাঠায় তা স্বাভাবিক VPN রুটই অনুসরণ করে।
এই সংকীর্ণ পরিসরই উদ্দেশ্য। সুরক্ষিত সকেট আপনার HTTP ক্লায়েন্ট কীভাবে নাম সমাধান করে, আপনার অ্যানালিটিক্স কল কোন ইন্টারফেস ব্যবহার করে, বা পরে খোলা দ্বিতীয় সংযোগের কী হয়, এসব বদলায় না।
যে তিনটি শর্ত পরিসর ঠিক করে
প্রথম শর্ত হলো কেবল টানেল ট্রান্সপোর্টকেই বের হতে হবে কি না। অ্যাপের বাকি ট্রাফিক যদি এখনও VPN দিয়ে যাওয়ার কথা হয়, তবে সকেট সুরক্ষাই সঠিক পরিসর। দ্বিতীয় শর্ত হলো সকেট তৈরির নিয়ন্ত্রণ আপনার হাতে কি না। ভেতরে গভীরে নিজের সকেট খোলা কোনো লাইব্রেরি আপনাকেprotect() কল করার জায়গা দেয় না, যদি না সে কোনো হুক দেয় বা আগেই তৈরি সকেট নেয়। তৃতীয় শর্ত হলো অ্যাপকে সরাসরি লোকাল নেটওয়ার্ক বা captive portal-এ পৌঁছাতে হবে কি না, যা টানেল সচল রাখার চেয়ে ভিন্ন প্রয়োজন।
অ্যাপটিকেaddDisallowedApplication() দিয়ে বাদ দেওয়া হলো ভোঁতা হাতিয়ার। এটি অ্যাপের প্রতিটি সংযোগ VPN থেকে সরিয়ে দেয়, যেগুলো আপনি দেখতে চেয়েছিলেন সেগুলোসহ, আর কিছু ডিভাইসে লোকাল ডিসকভারির আচরণও বদলে দেয়।
তৃতীয় বিকল্প হলো ট্রান্সপোর্টকে বেছে নেওয়া নেটওয়ার্কে বেঁধে দেওয়া:bindProcessToNetwork() অথবা সকেট-স্তরের নেটওয়ার্ক হ্যান্ডেল দিয়ে। এটি তখন কাজে লাগে যখন ডিভাইসে একই সঙ্গে Wi-Fi ও সেলুলার থাকে এবং আপনি চান টানেল নির্দিষ্ট একটি আপলিংক দিয়ে চলুক।
ট্রান্সপোর্ট তৈরি হওয়ার সময়ই এটি কল করুন
কল করুন protect() ট্রান্সপোর্ট তৈরির একই ব্লকে,connect() বাsend() এর আগে। কলটি যদি false ফেরায়, সকেট বন্ধ করুন এবং সেটআপ ব্যর্থ করুন; চালিয়ে গেলে এমন ট্রান্সপোর্ট হাতে থাকে যার প্যাকেট আপনার নিজের ইন্টারফেসে ফিরে আসতে পারে।
আকৃতিটি এক জায়গায় রাখার মতোই ছোট:
DatagramSocket transport = new DatagramSocket();
if (!protect(transport)) {
transport.close();
throw new IOException("transport not protected");
}
transport.connect(serverAddress);এখানে তিনটি বিষয় দংশন করে। প্রথমত,বুলিয়ানই আপনার পাওয়া একমাত্র সংকেত, তাই ব্যর্থতা এমন প্রসঙ্গসহ লগ করুন যা প্রত্যাহৃত সম্মতি আর প্রত্যাখ্যাত কলের পার্থক্য বোঝায়। দ্বিতীয়ত,protect() সকেট ঢাকে, ডেসক্রিপ্টর নম্বর নয়: সকেট বন্ধ করে পরে সেই একই পূর্ণসংখ্যা অন্য সকেটে ব্যবহার করলে নতুন সকেটটি সুরক্ষিত থাকে না। তৃতীয়ত, কোনো নেটিভ লাইব্রেরি ট্রান্সপোর্ট খুললে নেটিভ কোড সংযোগ করার আগেই ডেসক্রিপ্টরটি সুরক্ষিত করুন, নইলে রুট আগেই বেছে নেওয়া হতে পারে।VpnService রেফারেন্স হলো আপনার লক্ষ্য API স্তর আসলে কোন ওভারলোডগুলো দেয় তা নিশ্চিত করার জায়গা।
শুধু সুখকর পথ নয়, ব্লক হওয়া পথও পরীক্ষা করুন
টানেল চালু রেখে যাচাই করুন, কারণ এটিই একমাত্র অবস্থা যেখানে দুটি পথ আলাদা হতে পারে। সুরক্ষিত ট্রান্সপোর্ট দিয়ে একটি অনুরোধ পাঠান, আর protect() কখনও কল করেনি এমন কোড পথ থেকে আরেকটি, তারপর দূর প্রান্ত কী দেখে তা তুলনা করুন: সুরক্ষিত সংযোগের উৎস হওয়া উচিত অন্তর্নিহিত নেটওয়ার্ক, আর অসুরক্ষিতটি টানেলের নিজস্ব ঠিকানা দেখায় ও টানেলের বাইট কাউন্টার নড়ায়। ডিভাইসেss বাnetstat রেডিও থেকে কিছু বেরোনোর আগেই সেই বিভাজন দেখায়।
প্রত্যাহার আলাদাভাবে পরীক্ষা করুন, কারণ সম্মতির পরিবর্তন আপনার সকেট কোড স্পর্শ না করেই ইন্টারফেস ভেঙে দেয়। VPN সম্মতি প্রত্যাহার করুন বা সার্ভিস বন্ধ করুন, ট্রান্সপোর্ট নতুন করে তৈরি করুন এবং নিশ্চিত করুন যেprotect() এখনও true ফেরায় এবং সম্মতি আবার দেওয়া হলে ট্রান্সপোর্ট আবার সংযুক্ত হয়।
সুরক্ষিত অনুরোধ যদি তবুও টানেল অনুসরণ করে, তবে সুরক্ষা কলটি সম্ভবত সকেট ইতিমধ্যে রুট হওয়ার পরে ঘটছে। এটি আরও আগে সরান এবং আবার পরীক্ষা করুন।
সিদ্ধান্তটি ট্রান্সপোর্ট সেটআপের পাশে লিখে রাখুন: কোন সকেট সুরক্ষিত, কোন অ্যাপ ট্রাফিক বাদ, আর সুরক্ষা ব্যর্থ হলে অ্যাপ কী করে। এই লাইনটিই পরবর্তী রিফ্যাক্টরকে একটি পরীক্ষা ব্যর্থ হওয়ার কারণে বাদ দেওয়াকে পুরো অ্যাপে বিস্তৃত করতে বাধা দেয়। এটি পরের ব্যক্তিকে ম্যানিফেস্ট উল্টে না দেখেই উদ্দেশ্য যাচাইয়ের উপায়ও দেয়।