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

შემადარებელი იშვიათად არის დამნაშავე

პირველი, რაც უნდა გავამიჯნოთ, არის დაბლოკილი და დაზიანებული. დაბლოკილი სახელი სწრაფად და ხილულად უნდა ჩავარდეს, რადგან ბრაუზერი იღებს პასუხს, რომ სახელი არ არსებობს და ჩერდება. დაზიანებული სახელი ჩერდება, ხელახლა ცდის IPv6-ით, გადადის სხვა ტრანსპორტზე და გიტოვებთ მბრუნავი ინდიკატორით. თუ ხედავთ მბრუნავ ინდიკატორს, თქვენი ნებადართული სია, სავარაუდოდ, პასუხობს ისეთი რამით, რითაც კლიენტი ვერაფერს გააკეთებს.

ცარიელი A ჩანაწერი კლასიკური შეცდომაა. NOERROR-ის დაბრუნება ნულოვანი პასუხებით ვალიდურ პასუხად გამოიყურება, ამიტომ stub რეზოლვერი მას იღებს, ბრაუზერი ხელახლა ცდის, ცდის AAAA-ს, ცდის სხვა რეზოლვერს და გაცილებით გვიან ნებდება. პასუხის კოდი 3, ანუ NXDOMAIN, კითხვის სექციის გამეორებით და ტრანზაქციის ID-ის კოპირებით, საუბარს მაშინვე ამთავრებს. გამოიყენეთ ის ყოველი სახელისთვის, რომელსაც განზრახ უარყოფთ.

IPv6-იც იმავე გადაწყვეტილებას იმსახურებს და არა ნაგულისხმევ მნიშვნელობას. თუ A-ზე პასუხობთ NXDOMAIN-ით და AAAA-ს გაუშვებთ, კლიენტს შეუძლია დაბლოკილ სახელამდე IPv6-ით მივიდეს და ფილტრი ჟონავს. ზოგიერთი იმპლემენტაცია დაბლოკილ AAAA მოთხოვნებს loopback მისამართით პასუხობს, რომ კავშირი მაშინვე ჩავარდეს ალტერნატივაზე გადასვლის ნაცვლად. აირჩიეთ ერთი პოლიტიკა, გამოიყენეთ ის ორივე ჩანაწერის ტიპზე და ორივე ჟურნალში ჩაწერეთ.

მარშრუტი, რომელიც ყველაფერს იჭერს, ყველაფერს ფლობს

მხოლოდ DNS-ზე დაფუძნებული დიზაინი არასდროს ამატებს addRoute("0.0.0.0", 0)-ს, ამიტომ TUN ინტერფეისში მხოლოდ მოთხოვნები შედის და დანარჩენი ყველაფერი ქვედა ქსელს იყენებს. ეს არის უსაფრთხო ფორმა და ეს განმარტავს, რატომ ჩანს ზოგიერთი ნებადართული სია Wi-Fi-ზე მომუშავე და მობილურ ქსელში ვარდება.

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

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

გადაცემა არის ადგილი, სადაც შემდეგი ხაფანგი ზის. ოპერატორის რეზოლვერები ხშირად ცხოვრობენ კერძო მისამართზე, სადაც გვირაბი ვერ აღწევს, ამიტომ გადაცემული მოთხოვნა არსად მიდის და აპლიკაცია იუწყება კითხვის დროის ამოწურვას. დამტკიცებული მოთხოვნები გაუგზავნეთ რეზოლვერს, რომლის ხელმისაწვდომობაც იცით, და ჯერ ის სოკეტი გადაეცით VpnService.protect()-ს. დაუცველი სოკეტი მოთხოვნას თქვენსავე გვირაბში აბრუნებს, სადაც ის ისევ აპლიკაციამდე აღწევს და ტრიალებს, სანამ დროის ლიმიტი ამოქმედდება.

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

ზომა და საკონტროლო ჯამები უსიტყვოდ ვარდება

ჩუმი გადაგდებები ზომისგანაც მოდის. დიდი პასუხების ნაკრების მქონე DNS პასუხი ან უხვი ოფციებით TCP ხელის ჩამორთმევა შეიძლება აღემატებოდეს გზის MTU-ს, რომელიც არასდროს დაგიყენებიათ ცხადად; ფრაგმენტი ზემოთ ქრება და კლიენტი ან უფრო პატარათი ცდის ხელახლა, ან წყვეტს ცდას. ინტერფეისის MTU-ის 1280-ზე დაყენება კონსერვატიული არჩევანია, რომელიც მობილური გზების უმეტესობას უძლებს და ცხადი ყოფნა უკეთესია, ვიდრე იმ ნაგულისხმევი მნიშვნელობის მემკვიდრეობა, რომელიც არავის გაუზომავს.

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

რას არ გააკეთებს VpnService თქვენთვის

ორი ზღვარი ღირს იცოდეთ, სანამ მათ გარშემო დააპროექტებთ. არცერთ ჩვეულებრივ აპლიკაციას არ შეუძლია Wi-Fi-ის გარეთ სისტემური პროქსის ან PAC ფაილის დაყენება და ეს ნაწილი არ შეცვლილა. აპლიკაციაზე დამოკიდებული გზა შეიცვალა: API 29-მდე VpnService.Builder საერთოდ ვერ ატარებდა პროქსის, ხოლო API 29-დან setHttpProxy(ProxyInfo.buildPacProxy(uri)) პლატფორმას აძლევს PAC სკრიპტს VPN ქსელისთვის შესაფასებლად. შეაფასეთ წესები თქვენსავე კოდში, როცა ძველ API-ებს მიმართავთ ან როცა PAC მოდელი ვერ გამოხატავს წესს. UDP-იც უფასო არ არის: ბრაუზერები SOCKS პროქსის მეშვეობით მხოლოდ TCP-ს აგზავნიან და SOCKS5 კლიენტების უმეტესობა არასდროს ახორციელებს UDP ASSOCIATE-ს, ამიტომ პროქსიზე დაფუძნებული დიზაინი UDP-ს ყრის ან ჟონავს, სანამ TCP ჯანსაღად გამოიყურება.

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

შეამოწმეთ ამ თანმიმდევრობით

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

  1. ჩამოთვალეთ დაყენებული მარშრუტები და დაადასტურეთ, საერთოდ შედის თუ არა არა-DNS პაკეტები TUN ინტერფეისში.
  2. ჩაწერეთ ჟურნალში მოთხოვნის სახელი, გადაწყვეტილება და პასუხის კოდი ერთი დაბლოკილი და ერთი დამტკიცებული სახელისთვის.
  3. დაადასტურეთ, რომ რეზოლვერის სოკეტი დაცულია და არჩეული რეზოლვერი გვირაბის შიგნიდან პასუხობს.
  4. დაადასტურეთ ინტერფეისის MTU და ხელით აწყობილი ერთი პასუხის საკონტროლო ჯამი.
  5. გაიმეორეთ იგივე გვერდი Wi-Fi-ზე და მობილურ ქსელში, რადგან ოპერატორის რეზოლვერები და გზის MTU განსხვავდება.

თუ ხუთივე ძლებს და გვერდი მაინც ჩერდება, შემდეგი ეჭვმიტანილი თავად გადამცემია: შეადარეთ დაჭერილი მოთხოვნა დაჭერილ პასუხს და მოძებნეთ დაკარგული ბაიტების რაოდენობა ან ნახევრად დახურული სოკეტი. VpnService.Builder-ის ცნობარი მოიცავს მარშრუტის, DNS-ისა და MTU-ის ხელშეკრულებებს და protect() ცალკე VpnService გამოძახებაა და არა builder-ის ოფცია; დაკავშირებული ინტერფეისი მხოლოდ იმას ნიშნავს, რომ პირველი ხელშეკრულება შესრულდა.

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