Android VpnService ಸಂಪರ್ಕಗೊಳ್ಳುತ್ತದೆ ಆದರೆ ಯಾವುದೇ ಪ್ಯಾಕೆಟ್ ನೆಟ್ವರ್ಕ್ ತಲುಪುವುದಿಲ್ಲ
ಟನಲ್ ಚಾಲನೆಯಲ್ಲಿದೆ ಮತ್ತು ಪುಟಗಳು ಇನ್ನೂ ವಿಫಲವಾಗುತ್ತಿವೆ: VPN ಸರ್ವರ್ಗೆ ದೋಷ ಹೇರುವ ಮೊದಲು ಓದುವ ಮೋಡ್, ಸಾಕೆಟ್ ರಕ್ಷಣೆ, TCP ಬೆಂಬಲ ಮತ್ತು ರೂಟ್ ಪಟ್ಟಿಯನ್ನು ಪರಿಶೀಲಿಸಿ.
ಟನಲ್ ಮೇಲೆ ಬರುತ್ತದೆ, ಕೀ ಐಕಾನ್ ಕಾಣಿಸುತ್ತದೆ, ಆದರೆ ಬ್ರೌಸರ್ನ ಪ್ರತಿ ವಿನಂತಿಯೂ ಸಮಯ ಮೀರಿ ವಿಫಲವಾಗುತ್ತದೆ. VpnService ಆ್ಯಪ್ನಲ್ಲಿ ಈ ಸಂಯೋಜನೆ ಸಾಮಾನ್ಯವಾಗಿ ಓದುವ ಲೂಪ್ ಜೀವಂತವಾಗಿದೆ ಮತ್ತು ಔಟ್ಪುಟ್ ಅರ್ಧ ಮುರಿದಿದೆ ಎಂದು ಅರ್ಥ, ಸರ್ವರ್ ಹ್ಯಾಂಡ್ಶೇಕ್ ತಿರಸ್ಕರಿಸಿದೆ ಎಂದಲ್ಲ. Android ಈಗಾಗಲೇ ಇಂಟರ್ಫೇಸ್ ರಚಿಸಿ, ಆ್ಯಪ್ ಟ್ರಾಫಿಕ್ ಅದರೊಳಗೆ ಸರಿಸಿ, ನಿಮ್ಮ ಪ್ರಕ್ರಿಯೆಗೆ ಫೈಲ್ ಡಿಸ್ಕ್ರಿಪ್ಟರ್ ನೀಡಿದೆ. ಆ ಡಿಸ್ಕ್ರಿಪ್ಟರ್ ನಂತರದ ಎಲ್ಲವೂ ನಿಮ್ಮ ಕೋಡ್, ಮತ್ತು ಒಂದು ಕಾಣೆಯಾದ ಕರೆ ಇಡೀ ಸ್ಟ್ರೀಮ್ ನುಂಗಲು ಸಾಕು.
ಸಿಸ್ಟಮ್ ಏನು ಕೊಡುತ್ತದೆ, ಏನು ಕೊಡುವುದಿಲ್ಲ
establish() tun ಇಂಟರ್ಫೇಸ್ಗಾಗಿ ParcelFileDescriptor ಹಿಂತಿರುಗಿಸುತ್ತದೆ. ಸಿಸ್ಟಮ್ ಹೊರಹೋಗುವ IP ಪ್ಯಾಕೆಟ್ಗಳನ್ನು ಅದರೊಳಗೆ ಬರೆಯುತ್ತದೆ ಮತ್ತು ನಿಮ್ಮ ಪ್ರಕ್ರಿಯೆ ಅವನ್ನು ಓದಿ, ಎಲ್ಲಿಗೆ ಹೋಗುತ್ತವೆ ಎಂದು ನಿರ್ಧರಿಸಿ, ಸಾಮಾನ್ಯ ಸಾಕೆಟ್ ಮೂಲಕ ಕಳುಹಿಸುತ್ತದೆ ಎಂದು ನಿರೀಕ್ಷಿಸುತ್ತದೆ. ಕೆಳಗೆ ಕರ್ನಲ್ ಫಾರ್ವರ್ಡಿಂಗ್ ಇಲ್ಲ, ಆದ್ದರಿಂದ ಯಾರೂ ಓದದಿದ್ದರೆ ಪ್ಯಾಕೆಟ್ಗಳು ಬಿಡಲ್ಪಡುತ್ತವೆ ಮತ್ತು ಇಂಟರ್ಫೇಸ್ ಕೌಂಟರ್ಗಳು ಎಂದಿಗೂ ಚಲಿಸುವುದಿಲ್ಲ.
ಊಹಿಸುವ ಬದಲು ಎಣಿಸಿ ಪ್ರಾರಂಭಿಸಿ. ಪ್ರತಿ ಯಶಸ್ವಿ ಓದಿಗೆ ಕೌಂಟರ್ ಹೆಚ್ಚಿಸಿ ಮತ್ತು ಮೊದಲ ಕೆಲವು ಪ್ಯಾಕೆಟ್ಗಳ ಗಮ್ಯಸ್ಥಾನ ಹಾಗೂ ಪ್ರೋಟೋಕಾಲ್ ಲಾಗ್ ಮಾಡಿ. ಟ್ರಾಫಿಕ್ ಉತ್ಪಾದನೆಯಾಗುತ್ತಿರುವಾಗ ಕೌಂಟರ್ ಶೂನ್ಯವಾಗಿ ಉಳಿದರೆ, ದೋಷ ನಿಮ್ಮ ಫಾರ್ವರ್ಡಿಂಗ್ ಕೋಡ್ಗಿಂತ ಮೇಲಿದೆ, ಇದು ಹುಡುಕಾಟವನ್ನು builder ಸಂರಚನೆ ಮತ್ತು ಓದುವ ಮೋಡ್ಗೆ ಸೀಮಿತಗೊಳಿಸುತ್ತದೆ. ಕೌಂಟರ್ ಚಲಿಸಿ ಬ್ರೌಸರ್ ಇನ್ನೂ ವಿಫಲವಾದರೆ, ದೋಷ ಕಳುಹಿಸುವ ಅಥವಾ ಹಿಂತಿರುಗುವ ಮಾರ್ಗದಲ್ಲಿದೆ.
ಬ್ಲಾಕಿಂಗ್ ಓದು ಲೂಪ್ ಚಲಿಸುತ್ತದೆಯೇ ಎಂದು ನಿರ್ಧರಿಸುತ್ತದೆ
setBlocking(true) ಡಿಸ್ಕ್ರಿಪ್ಟರ್ ಅನ್ನು ಬ್ಲಾಕಿಂಗ್ ಮೋಡ್ಗೆ ಹಾಕುತ್ತದೆ ಮತ್ತು API 21 ರಿಂದ ಇದೆ. ಹಳೆಯ ಆವೃತ್ತಿಗಳಲ್ಲಿ ಪರಿಹಾರ ಚಿಕ್ಕ JNI ಸಹಾಯಕ, ಇದು ಕಚ್ಚಾ ಡಿಸ್ಕ್ರಿಪ್ಟರ್ನಲ್ಲಿ fcntl ಮೂಲಕ O_NONBLOCK ಅನ್ನು ಅಳಿಸುತ್ತದೆ. ಮೋಡ್ ಮುಖ್ಯ ಏಕೆಂದರೆ ಕಾಯುತ್ತಿರುವ ಪ್ಯಾಕೆಟ್ ಇಲ್ಲದ ಓದಿಗೆ ಏನು ಮಾಡಬಹುದು ಎಂದು ಅದು ನಿರ್ಧರಿಸುತ್ತದೆ.
ನಾನ್-ಬ್ಲಾಕಿಂಗ್ ಮೋಡ್ನಲ್ಲಿ ಆ ಓದು ತಕ್ಷಣ ಋಣಾತ್ಮಕ ಮೌಲ್ಯದೊಂದಿಗೆ ಹಿಂತಿರುಗುತ್ತದೆ, ಮತ್ತು ಫಲಿತಾಂಶವನ್ನು ನಿರ್ಲಕ್ಷಿಸುವ ಲೂಪ್ ಯಾವುದೇ ಟ್ರಾಫಿಕ್ ಚಲಿಸದೆ ಕೋರ್ ತಿರುಗಿಸುತ್ತದೆ. ಬ್ಲಾಕಿಂಗ್ ಮೋಡ್ನಲ್ಲಿ ಓದು ಕಾಯುತ್ತದೆ, ಇದು ಫಾರ್ವರ್ಡಿಂಗ್ ಥ್ರೆಡ್ಗೆ ಬೇಕಾದದ್ದು, ಆದರೆ ಆಗ ಥ್ರೆಡ್ ಅನ್ನು ತಡೆಯಲಾಗುವುದಿಲ್ಲ. ಡಿಸ್ಕ್ರಿಪ್ಟರ್ ಮುಚ್ಚುವುದು ಓದು ವಿಫಲವಾಗಲು ಬೆಂಬಲಿತ ಮಾರ್ಗ, ಇದರಿಂದ ಲೂಪ್ ಹೊರಬರಬಹುದು. ಪ್ರಕ್ರಿಯೆ ಕೊಲ್ಲುವುದು ಅಥವಾ ಥ್ರೆಡ್ ತಡೆಯುವುದು ಮುಂದಿನ ಪ್ರಾರಂಭಕ್ಕೆ ಇಂಟರ್ಫೇಸ್ಗೆ ಇನ್ನು ಹೊಂದದ ಡಿಸ್ಕ್ರಿಪ್ಟರ್ ಬಿಡಬಹುದು.
ಪ್ರತಿ ಕರೆಗೆ ಇಂಟರ್ಫೇಸ್ನ 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 ನಿಂದ ಸಂಪರ್ಕ ಮರುಹೊಂದಿಕೆ ಎಂದರೆ ನಿಮ್ಮ ಕೋಡ್ ಇನ್ನೂ ಓದುತ್ತಿರುವಾಗ ದೂರದ ತುದಿ ಮುಚ್ಚಿತು. ಕೆಟ್ಟ ವಿಳಾಸದ ದೋಷ ಹೆಡರ್ ಪಾರ್ಸಿಂಗ್ ಅಥವಾ ಆಫ್ಸೆಟ್ ದೋಷಕ್ಕೆ ಸೂಚಿಸುತ್ತದೆ, ನೆಟ್ವರ್ಕ್ಗಲ್ಲ.
ಕೆಲಸದ ಕ್ರಮ: ಬ್ಲಾಕಿಂಗ್ ಮೋಡ್ ಆನ್, ಪ್ರತಿ ಓದಿಗೆ ಒಂದು ಪ್ಯಾಕೆಟ್, ಹೆಡರ್ ಪಾರ್ಸ್ ಆಗಿದೆ, ಸಾಕೆಟ್ ರಕ್ಷಿಸಲಾಗಿದೆ, ಪೇಲೋಡ್ ಕಳುಹಿಸಲಾಗಿದೆ, ಹಸ್ತಾಂತರದಲ್ಲಿ ಸ್ವಚ್ಛ ಮುಚ್ಚುವಿಕೆ, ಮತ್ತು ಗಮ್ಯಸ್ಥಾನವನ್ನು ಒಳಗೊಳ್ಳುವ ರೂಟ್ ಪಟ್ಟಿ.