অ্যান্ড্রয়েড VPN অ্যাট্রিবিউশন: getConnectionOwnerUid বনাম /proc/net
অ্যান্ড্রয়েড 10 অ্যাপ থেকে /proc/net লুকায়। VPN এখনও প্যাকেট পায়, কিন্তু অ্যাট্রিবিউশন নিজস্ব টুপল ও অনুমতি নিয়মসহ getConnectionOwnerUid-এ চলে যায়।
অ্যান্ড্রয়েড 10 ও তার পরের সংস্করণে যে অ্যাপ /proc/net/tcp খোলে সে সকেট টেবিলের বদলে অ্যাক্সেস প্রত্যাখ্যান পায়। VPN ইন্টারফেসের কিছু যায় আসে না: প্যাকেট আসতেই থাকে, কারণ টানেল একটি রাউটিং সিদ্ধান্ত, ফাইলের অনুমতি নয়। যা বদলেছে তা আরও সংকীর্ণ প্রশ্নের উত্তর: “কোন অ্যাপ্লিকেশন এই সংযোগের মালিক?” বিকল্প হলো ConnectivityManager.getConnectionOwnerUid, প্রতি-সংযোগ সমর্থিত কোয়েরি, আর পুরোনো অভ্যাস ও নতুন API-র মধ্যে বাছাই নির্ভর করে আপনার কাছে আসলে তিনটি কাজের কোনটি আছে তার উপর: প্যাকেট গ্রহণ, ফ্লো অ্যাট্রিবিউশন, নাকি ব্যবহারের হিসাব।
মালিক-প্রশ্নের দুটি উত্তর
API 29-এর আগে একটি বিশেষাধিকারপ্রাপ্ত বা root প্রসেস কার্নেলের সকেট টেবিল পড়ে চার-টুপল মিলিয়ে মালিক UID জানতে পারত। এটি এক ফাইলে পুরো ডিভাইসের তালিকা দিত। API 29 থেকে ফাইলসিস্টেম দৃশ্য সীমিত, এবং সমর্থিত পথ হলো প্রোটোকল, স্থানীয় ঠিকানা ও দূরবর্তী ঠিকানা দিয়ে প্রতি-সংযোগ কোয়েরি।
| Question | Legacy socket tables | getConnectionOwnerUid |
|---|---|---|
| Who owns this flow? | Scan and match the tuple | Ask once per tuple |
| Device-wide inventory? | Yes, when readable | No, one flow at a time |
| Historical usage? | No | No; that is NetworkStatsManager |
| Works without root? | No on modern releases | Yes, for authorized callers |
তুলনাটি “পুরোনো বনাম নতুন” নয়। এটি তিনটি ভিন্ন কাজ, যা আগে একটি পাঠযোগ্য ফাইলে মিটত এবং এখন তিনটি ভিন্ন ইন্টারফেসে তিনটি ভিন্ন চুক্তিতে মেটে।
স্থানীয় ঠিকানাই অ্যাপের প্রান্ত
মেথড সিগনেচার একটি প্রোটোকল, একটি স্থানীয় সকেট ঠিকানা ও একটি দূরবর্তী সকেট ঠিকানা নেয়। “স্থানীয়” মানে সংযোগের অ্যাপের দিক, এমন নয় যে প্রান্তটি পরীক্ষার মুহূর্তে প্যাকেটের উৎস হয়ে গেছে। দূরবর্তী সার্ভার থেকে অ্যাপে ফেরা প্যাকেটের উৎস ও গন্তব্য এই সংজ্ঞার সাপেক্ষে উল্টো।
ConnectivityManager cm = getSystemService(ConnectivityManager.class);
int uid = cm.getConnectionOwnerUid(
OsConstants.IPPROTO_TCP, appLocalAddress, appRemoteAddress);এই দিক-ভুলটাই কার্যকর কোয়েরি ভুল উত্তর বা কোনো উত্তর না দেওয়ার সবচেয়ে সাধারণ কারণ। কলের আগে দুটি প্রান্তই লগ করুন এবং অ্যাপটি সত্যিই যে সংযোগ খুলেছে তার সঙ্গে জোড়াটি মিলিয়ে নিন। ঠিকানা পরিবারও গুরুত্বপূর্ণ: IPv4-ম্যাপ করা ঠিকানা ও নেটিভ IPv6 ঠিকানা ভিন্ন টুপল, আর একই পোর্টে TCP ও UDP ফ্লো-ও ভিন্ন।
অনুমোদন ও অজানা ফলাফল চুক্তির অংশ
কোয়েরিটি অনুমোদিত কলারের মধ্যে সীমিত, যার মধ্যে সংশ্লিষ্ট ব্যবহারকারীর সক্রিয় VPN অ্যাপও আছে। সম্পর্কহীন মনিটরিং অ্যাপ ধরে নিতে পারে না যে সে অন্য প্রোফাইলের সংযোগ গণনা করতে পারবে, আর অননুমোদিত কল বন্ধুত্বপূর্ণ ত্রুটির বদলে নিরাপত্তা ব্যতিক্রম ছুড়তে পারে। দুই ফলাফলই স্পষ্টভাবে সামলান।
অনুপস্থিত মালিক কোনো প্যাকেজ নাম নয়। প্যাকেট ও কোয়েরির মধ্যে ফ্লো বন্ধ হয়ে থাকতে পারে, টুপল অসম্পূর্ণ হতে পারে, বা কলারকে জানার অনুমতি নাও থাকতে পারে। প্রথম সফল উত্তর ক্যাশ করে পরে পুনর্ব্যবহার করলে নতুন সংযোগ পুরোনো অ্যাপকে আরোপিত হয়, যা অজানা বলে জানানোর চেয়ে খারাপ।
অ্যাট্রিবিউশন ব্যর্থ হলে ট্র্যাফিকের তবুও সিদ্ধান্ত দরকার: নীতি যেখানে দাবি করে সেখানে ব্লক করুন, শুধু আপনার বোঝা পরিধি অনুমোদন করুন, বা ফাঁকটি দেখান। এই ফলব্যাক ডিজাইনের অংশ, মন্তব্যের নয়।
হিসাব একটি ভিন্ন প্রশ্ন
NetworkStatsManager নিজস্ব অ্যাক্সেস নিয়মে ব্যবহার রিপোর্ট করে। এটি বলতে পারে একটি UID একটি সময়ে কতটা স্থানান্তর করেছে; এটি কোনো ইচ্ছামতো জীবন্ত প্যাকেটের মালিক বলতে পারে না। নেটওয়ার্ক সক্ষমতা নেটওয়ার্কের বৈশিষ্ট্য বর্ণনা করে, সকেটের তালিকা নয়। তিনটি মেশালে এমন ড্যাশবোর্ড হয় যা সামঞ্জস্যপূর্ণ দেখায় কিন্তু নয়।
কোন অ্যাপ টানেল ব্যবহার করে ঠিক করার সরল ক্ষেত্রে, অ্যান্ড্রয়েডের সমর্থিত অনুমোদিত ও নিষিদ্ধ অ্যাপ্লিকেশন তালিকা কোনো স্ক্র্যাপিং ছাড়াই নীতিটি প্রকাশ করে। যে ক্ষেত্রে সত্যিই দরকার সেখানে প্রতি-ফ্লো অ্যাট্রিবিউশন রাখুন, এবং দিক, অনুমতি ও অজানা অবস্থা একসঙ্গে সামলানো একটি রক্ষণাবেক্ষণযোগ্য বাস্তবায়নের জন্য বাজেট রাখুন।
কাজ দেখে টুল বাছুন, তারপর প্রান্ত পরীক্ষা করুন
প্রয়োজন টানেল নির্বাচন হলে প্ল্যাটফর্ম তালিকা ব্যবহার করুন। লাইভ অ্যাট্রিবিউশন হলে মালিক কোয়েরি ব্যবহার করুন এবং প্রতিটি উত্তরহীন টুপলকে অজানা ধরুন। ঐতিহাসিক মোট হলে stats API ব্যবহার করুন। তারপর সেই তিনটি প্রান্ত পরীক্ষা করুন যা সরল বাস্তবায়ন ভাঙে: বিপরীত দিকের প্যাকেট, কোয়েরির আগে বন্ধ হওয়া ফ্লো, এবং যে কলার সক্রিয় VPN নয়।
এর কোনোটির জন্য SELinux বন্ধ করা, ফোন root করা বা কার্নেল টেবিল বিশ্বজুড়ে পাঠযোগ্য করা লাগে না। সীমাবদ্ধতাটাই মূল কথা: প্ল্যাটফর্ম অ্যাট্রিবিউশনকে একটি চুক্তির পিছনে সরিয়েছে যাতে উত্তরটি বৈধভাবে প্রয়োজন এমন উপাদানের কাছে থাকে, অন্য কারও কাছে নয়।