Android 10-სა და უფრო ახალ ვერსიებში აპი, რომელიც ხსნის /proc/net/tcp-ს, socket-ების ცხრილის ნაცვლად წვდომის უარყოფას იღებს. VPN ინტერფეისს ეს არ აინტერესებს: პაკეტები მაინც მოდის, რადგან გვირაბი მარშრუტიზაციის გადაწყვეტილებაა და არა ფაილის ნებართვა. შეიცვალა პასუხი უფრო ვიწრო კითხვაზე: „რომელი აპი ფლობს ამ კავშირს?“ ჩამნაცვლებელია ConnectivityManager.getConnectionOwnerUid, მხარდაჭერილი მოთხოვნა თითო კავშირზე, და არჩევანი ძველ ჩვევასა და ახალ API-ს შორის დამოკიდებულია იმაზე, თუ რომელი სამი სამუშაო გაქვთ სინამდვილეში: პაკეტების მიღება, ნაკადის ატრიბუცია თუ მოხმარების შეჯამება.

მფლობელის კითხვაზე პასუხის ორი გზა

API 29-მდე პრივილეგირებულ ან root პროცესს შეეძლო წაეკითხა ბირთვის socket-ების ცხრილები, შეედარებინა ოთხეული და გაეგო მფლობელი UID. ეს ერთ ფაილში მთელი მოწყობილობის ინვენტარს იძლეოდა. API 29-დან ფაილური სისტემის ხედი შეზღუდულია, და მხარდაჭერილი გზაა მოთხოვნა თითო კავშირზე პროტოკოლით, ლოკალური მისამართითა და დისტანციური მისამართით.

QuestionLegacy socket tablesgetConnectionOwnerUid
Who owns this flow?Scan and match the tupleAsk once per tuple
Device-wide inventory?Yes, when readableNo, one flow at a time
Historical usage?NoNo; that is NetworkStatsManager
Works without root?No on modern releasesYes, for authorized callers

შედარება „ძველი ახლის წინააღმდეგ“ არ არის. ეს სამი განსხვავებული სამუშაოა, რომლებსაც ადრე ერთი წაკითხვადი ფაილი აკმაყოფილებდა, ახლა კი სამი განსხვავებული ინტერფეისი სამი განსხვავებული კონტრაქტით აკმაყოფილებს.

ლოკალური მისამართი აპის ბოლოა

მეთოდის ხელმოწერა იღებს პროტოკოლს, ლოკალურ socket-ის მისამართს და დისტანციურ socket-ის მისამართს. „ლოკალური“ ნიშნავს კავშირში აპის მხარეს და არა იმ ბოლოს, რომელიც შემოწმების მომენტში შემთხვევით პაკეტის წყაროა. დისტანციური სერვერიდან აპისკენ დაბრუნებულ პაკეტს ამ განსაზღვრების მიმართ წყარო და დანიშნულება შეცვლილი აქვს.

ConnectivityManager cm = getSystemService(ConnectivityManager.class);
int uid = cm.getConnectionOwnerUid(
    OsConstants.IPPROTO_TCP, appLocalAddress, appRemoteAddress);

ეს მიმართულების შეცდომა ყველაზე გავრცელებული მიზეზია, რომ მუშა მოთხოვნა არასწორ პასუხს იძლევა, ან საერთოდ არაფერს. ჩაწერეთ ორივე ბოლო გამოძახებამდე და გადაამოწმეთ წყვილი იმ კავშირთან, რომელიც აპმა ნამდვილად გახსნა. მისამართების ოჯახიც მნიშვნელოვანია: IPv4-ით დამაპირებული მისამართი და მშობლიური IPv6 მისამართი სხვადასხვა ოთხეულია, ისევე როგორც TCP და UDP ნაკადები ერთსა და იმავე პორტებზე.

ავტორიზაცია და უცნობი შედეგები კონტრაქტის ნაწილია

მოთხოვნა შემოიფარგლება ავტორიზებული გამომძახებლებით, მათ შორის შესაბამისი მომხმარებლის აქტიური VPN აპით. უკავშირო მონიტორინგის აპი ვერ ივარაუდებს, რომ სხვა პროფილის კავშირებს ჩამოთვლის, და არაავტორიზებულმა გამოძახებამ შეიძლება უსაფრთხოების გამონაკლისი გაისროლოს მეგობრული შეცდომის ნაცვლად. ორივე შედეგი ცალსახად დაამუშავეთ.

დაკარგული მფლობელი პაკეტის სახელი არ არის. ნაკადი შეიძლება დაიხურა პაკეტსა და მოთხოვნას შორის, ოთხეული შეიძლება არასრული იყოს, ან გამომძახებელს უბრალოდ არ აქვს ცოდნის უფლება. პირველი წარმატებული პასუხის ქეშირება და მოგვიანებით ხელახლა გამოყენება ახალ კავშირს ძველ აპს მიაწერს, რაც უარესია, ვიდრე უცნობის შეტყობინება.

როცა ატრიბუცია ვერ ხერხდება, ტრაფიკს მაინც სჭირდება გადაწყვეტილება: დაბლოკეთ იქ, სადაც პოლიტიკა მოითხოვს, დაუშვით მხოლოდ თქვენთვის გასაგები არეალი, ან აჩვენეთ ხარვეზი. ეს სარეზერვო გზა დიზაინს ეკუთვნის და არა კომენტარს.

ბუღალტერია სხვა კითხვაა

NetworkStatsManager მოხმარებას საკუთარი წვდომის წესებით იუწყება. მას შეუძლია გითხრათ, რამდენი გადასცა UID-მა პერიოდში; მას არ შეუძლია გითხრათ თვითნებური ცოცხალი პაკეტის მფლობელი. ქსელის შესაძლებლობები ქსელის თვისებებს აღწერს და არა socket-ების კატალოგს. სამივის შერევა იძლევა დაფებს, რომლებიც თანმიმდევრულად გამოიყურება და ასე არ არის.

იმ მარტივ შემთხვევაში, როცა წყვეტთ, რომელი აპები იყენებენ გვირაბს, Android-ის მხარდაჭერილი დაშვებული და აკრძალული აპების სიები უკვე გამოხატავენ პოლიტიკას ყოველგვარი scraping-ის გარეშე. შეინახეთ ნაკადის ატრიბუცია იმ შემთხვევებისთვის, რომლებსაც ნამდვილად სჭირდებათ, და ბიუჯეტი გამოყავით შენახული იმპლემენტაციისთვის, რომელიც ერთად ამუშავებს მიმართულებას, ნებართვებსა და უცნობ მდგომარეობებს.

აირჩიეთ ხელსაწყო საქმის მიხედვით, შემდეგ გამოსცადეთ კიდეები

თუ მოთხოვნა გვირაბის არჩევაა, გამოიყენეთ პლატფორმის სია. თუ ეს ცოცხალი ატრიბუციაა, გამოიყენეთ მფლობელის მოთხოვნა და ყოველი უპასუხო ოთხეული უცნობად მიიჩნიეთ. თუ ეს ისტორიული ჯამებია, გამოიყენეთ stats API. შემდეგ გამოსცადეთ სამი კიდე, რომლებიც ამტვრევს გულუბრყვილო იმპლემენტაციებს: საწინააღმდეგო მიმართულების პაკეტი, მოთხოვნამდე დახურული ნაკადი და გამომძახებელი, რომელიც აქტიური VPN არ არის.

ამათგან არაფერი მოითხოვს SELinux-ის გამორთვას, ტელეფონის root-ს ან ბირთვის ცხრილების გლობალურად წაკითხვადობას. შეზღუდვა სწორედ არსია: პლატფორმამ ატრიბუცია კონტრაქტის უკან გადასცა, რათა პასუხი ხელმისაწვდომი იყოს იმ კომპონენტისთვის, რომელსაც კანონიერად სჭირდება, და არავისთვის სხვისთვის.

დაკავშირებული სტატიები