Android VpnService కనెక్ట్ అవుతుంది కానీ ఏ ప్యాకెట్ నెట్వర్క్కు చేరుకోదు
టన్నెల్ నడుస్తోంది, పేజీలు ఇంకా విఫలమవుతున్నాయి: VPN సర్వర్ను నిందించే ముందు చదివే మోడ్, సాకెట్ రక్షణ, TCP మద్దతు మరియు మార్గాల జాబితాను తనిఖీ చేయండి.
టన్నెల్ పైకి వస్తుంది, కీ చిహ్నం కనిపిస్తుంది, కానీ బ్రౌజర్లోని ప్రతి అభ్యర్థన ఇప్పటికీ సమయం ముగిసి విఫలమవుతుంది. VpnService యాప్లో ఈ కలయిక సాధారణంగా చదివే లూప్ సజీవంగా ఉందని, అవుట్పుట్ సగం పాడైందని అర్థం, సర్వర్ హ్యాండ్షేక్ను తిరస్కరించిందని కాదు. Android ఇప్పటికే ఇంటర్ఫేస్ను సృష్టించి, యాప్ ట్రాఫిక్ను దానిలోకి తరలించి, మీ ప్రక్రియకు ఫైల్ డిస్క్రిప్టర్ను ఇచ్చింది. ఆ డిస్క్రిప్టర్ తర్వాత అంతా మీ కోడ్, ఒక తప్పిపోయిన కాల్ మొత్తం స్ట్రీమ్ను మింగడానికి సరిపోతుంది.
సిస్టమ్ ఏమి ఇస్తుంది, ఏమి ఇవ్వదు
establish() tun ఇంటర్ఫేస్ కోసం ParcelFileDescriptor ఇస్తుంది. సిస్టమ్ బయటకు వెళ్లే IP ప్యాకెట్లను అందులో రాస్తుంది మరియు మీ ప్రక్రియ వాటిని చదివి, ఎక్కడికి వెళ్లాలో నిర్ణయించి, సాధారణ సాకెట్ ద్వారా పంపుతుందని ఆశిస్తుంది. కింద కెర్నల్ ఫార్వర్డింగ్ లేదు, కాబట్టి ఎవరూ చదవనప్పుడు ప్యాకెట్లు పడవేయబడతాయి మరియు ఇంటర్ఫేస్ కౌంటర్లు ఎప్పుడూ కదలవు.
ఊహలకు బదులు లెక్కించడం ప్రారంభించండి. ప్రతి విజయవంతమైన పఠనంపై కౌంటర్ పెంచి, మొదటి ప్యాకెట్ల గమ్యం మరియు ప్రోటోకాల్ను లాగ్ చేయండి. ట్రాఫిక్ ఉత్పత్తి అవుతున్నప్పుడు కౌంటర్ సున్నాలో ఉంటే, లోపం మీ ఫార్వర్డింగ్ కోడ్ పైన ఉంది, ఇది వెతుకుడును builder కాన్ఫిగరేషన్ మరియు పఠన మోడ్కు కుదిస్తుంది. కౌంటర్ కదిలినా బ్రౌజర్ విఫలమైతే, లోపం పంపే లేదా తిరిగి వచ్చే మార్గంలో ఉంది.
బ్లాకింగ్ పఠనం లూప్ కదులుతుందో లేదో నిర్ణయిస్తుంది
setBlocking(true) డిస్క్రిప్టర్ను బ్లాకింగ్ మోడ్లోకి పెడుతుంది మరియు API 21 నుండి ఉంది. పాత విడుదలల్లో పరిష్కారం, ముడి డిస్క్రిప్టర్పై fcntl ద్వారా O_NONBLOCK తొలగించే చిన్న JNI సహాయకుడు. మోడ్ ముఖ్యం ఎందుకంటే వేచి ఉన్న ప్యాకెట్ లేని పఠనం ఏమి చేయగలదో అదే నిర్ణయిస్తుంది.
నాన్-బ్లాకింగ్ మోడ్లో ఆ పఠనం వెంటనే ఋణాత్మక విలువతో తిరిగి వస్తుంది, ఫలితాన్ని పట్టించుకోని లూప్ ఏ ట్రాఫిక్ కదిలించకుండా కోర్ తిప్పుతుంది. బ్లాకింగ్ మోడ్లో పఠనం వేచి ఉంటుంది, ఫార్వర్డింగ్ థ్రెడ్కు అదే కావాలి, కానీ అప్పుడు థ్రెడ్ను ఆపలేము. పఠనాన్ని విఫలం చేయడానికి మద్దతు ఉన్న మార్గం డిస్క్రిప్టర్ను మూసివేయడం, అప్పుడు లూప్ బయటకు వెళ్లగలదు. ప్రక్రియను చంపడం లేదా థ్రెడ్ను ఆపడం తదుపరి ప్రారంభాన్ని ఇంటర్ఫేస్కు సరిపోని డిస్క్రిప్టర్తో వదిలివేయవచ్చు.
ప్రతి కాల్లో ఇంటర్ఫేస్ 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 నుండి కనెక్షన్ రీసెట్ అంటే మీ కోడ్ ఇంకా చదువుతుండగా దూరపు చివర మూసుకుపోయింది. తప్పు చిరునామా లోపం హెడర్ పార్సింగ్ లేదా ఆఫ్సెట్ బగ్ వైపు చూపుతుంది, నెట్వర్క్ వైపు కాదు.
పని క్రమం: బ్లాకింగ్ మోడ్ ఆన్, ప్రతి పఠనానికి ఒక ప్యాకెట్, హెడర్ పార్స్ చేయబడింది, సాకెట్ రక్షించబడింది, పేలోడ్ పంపబడింది, అప్పగింపులో శుభ్రమైన మూసివేత మరియు గమ్యాన్ని కవర్ చేసే మార్గాల జాబితా.