Android VpnService: TUN ಓದು ನಿಂತುಕೊಳ್ಳುವುದು ಮತ್ತು ENOBUFS ಬರವಣಿಗೆ ದೋಷಗಳ ನಡುವಿನ ವ್ಯತ್ಯಾಸ
ಎಂದಿಗೂ ಮರಳದ ಓದು ಮತ್ತು ENOBUFS ನಿಂದ ವಿಫಲವಾಗುವ ಬರವಣಿಗೆ ವಿರುದ್ಧ ಕಾರಣಗಳನ್ನು ಹೊಂದಿವೆ. ಸರಿಪಡಿಸುವಿಕೆಯನ್ನು ಆಯ್ಕೆ ಮಾಡಲು ಘೋಷಿತ ವಿಂಡೋ ಮತ್ತು ಪ್ಯಾಕೆಟ್ ಉದ್ದವನ್ನು ಅಳೆಯಿರಿ.
ಒಂದೇ VpnService ಲೂಪ್ನಲ್ಲಿ ಎರಡು ಲಕ್ಷಣಗಳು ಕಾಣಿಸಿಕೊಳ್ಳುತ್ತವೆ ಮತ್ತು ಎರಡನ್ನೂ ಒಂದೇ ವಿಷಯಕ್ಕೆ ದೂಷಿಸಲಾಗುತ್ತದೆ: ಎಂದಿಗೂ ಮರಳದ ಓದುಗ, ಮತ್ತು ENOBUFS ನಿಂದ ವಿಫಲವಾಗುವ ಬರವಣಿಗೆ. ಇವು ಒಂದೇ ಬಗ್ನ ರೂಪಾಂತರಗಳಲ್ಲ. ನಿಂತುಹೋದ ಓದು ಪೀರ್ನೊಂದಿಗೆ ಹರಿವು ನಿಯಂತ್ರಣದ ಬಗ್ಗೆ ಭಿನ್ನಾಭಿಪ್ರಾಯ; ವಿಫಲವಾದ ಬರವಣಿಗೆ ಇಂಟರ್ಫೇಸ್ ಸ್ವೀಕರಿಸದ ಪ್ಯಾಕೆಟ್. ಅವುಗಳನ್ನು ಒಂದೇ ಸಮಸ್ಯೆ ಎಂದು ಪರಿಗಣಿಸಿದರೆ, ಎಂದಿಗೂ ಸಂಬಂಧಿಸದ ಬಫರ್ಗಳನ್ನು ಟ್ಯೂನ್ ಮಾಡುವುದರಲ್ಲಿ ಒಂದು ದಿನ ಕಳೆಯುತ್ತೀರಿ. ಕೆಳಗಿನ ವಿಭಜನೆ ಲೂಪ್ನ ಯಾವ ಅರ್ಧವನ್ನು ಮೊದಲು ಅಳೆಯಬೇಕೆಂದು ನಾನು ನಿರ್ಧರಿಸುವ ರೀತಿ.
ಒಂದು ಲೂಪ್, ಎರಡು ಸ್ವತಂತ್ರ ವೈಫಲ್ಯ ಬಿಂದುಗಳು
ನಿಮ್ಮ ಸೇವೆ TUN ಫೈಲ್ ಡಿಸ್ಕ್ರಿಪ್ಟರ್ನಿಂದ IP ಪ್ಯಾಕೆಟ್ ಓದುತ್ತದೆ, ಅದನ್ನು ಪರಿಶೀಲಿಸುತ್ತದೆ ಮತ್ತು ಅದೇ ಡಿಸ್ಕ್ರಿಪ್ಟರ್ಗೆ ಉತ್ತರ ಬರೆಯುತ್ತದೆ. ಆ ಮಾರ್ಗದಲ್ಲಿ ಮುರಿಯುವ ಎಲ್ಲವೂ ಆ ಎರಡು ಕರೆಗಳಲ್ಲಿ ಒಂದರಲ್ಲಿ ಕಾಣಿಸಿಕೊಳ್ಳುತ್ತದೆ, ಆದ್ದರಿಂದ ಎರಡನ್ನೂ ಟನೆಲ್ ಮುರಿದಿದೆ ಎಂದು ವರದಿ ಮಾಡಲಾಗುತ್ತದೆ. ಕರೆಗಳಿಗೆ ಬೇರೆ ಬೇರೆ ಒಪ್ಪಂದಗಳಿವೆ. ಓದು ಕರ್ನಲ್ ನಿಮಗೆ ಪ್ಯಾಕೆಟ್ ನೀಡುವವರೆಗೆ ಕಾಯುತ್ತದೆ, ಮತ್ತು ಬರವಣಿಗೆ ಕರ್ನಲ್ಗೆ ನಿರಾಕರಿಸಲು ಅಧಿಕಾರವಿರುವ ಪ್ಯಾಕೆಟ್ ನೀಡುತ್ತದೆ.
ಓದುಗಳು ಯೋಚಿಸಲು ಸುಲಭವಾದ ಅರ್ಧ. ಏನನ್ನೂ ಮರಳಿಸದ ಓದು ಎಂದಿಗೂ ಬಾರದ ಸಂಚಾರಕ್ಕಾಗಿ ಕಾಯುತ್ತಿದೆ ಅಥವಾ ಪೀರ್ ಕಳುಹಿಸುವುದನ್ನು ನಿಲ್ಲಿಸಿದ್ದರಿಂದ ಕಾಯುತ್ತಿದೆ.
ನಿಂತುಹೋದ ಓದು ಹರಿವು ನಿಯಂತ್ರಣದ ಭಿನ್ನಾಭಿಪ್ರಾಯ
TUN ಸಾಧನವನ್ನು ಓದುವುದು ಪ್ಯಾಕೆಟ್ ಲಭ್ಯವಾಗುವವರೆಗೆ ತಡೆಯುತ್ತದೆ. ಅದು ವಿನ್ಯಾಸಗೊಳಿಸಿದ ನಡವಳಿಕೆ, ಮತ್ತು ಆದ್ದರಿಂದ read ಒಳಗೆ ನಿಂತಿರುವ ಥ್ರೆಡ್ ನಿಷ್ಕ್ರಿಯ ಲಿಂಕ್ನಲ್ಲಿ ಸಾಮಾನ್ಯವಾಗಿ ಕಾಣುತ್ತದೆ. ನಿಮ್ಮ ಸ್ವಂತ TCP ಸ್ಟ್ಯಾಕ್ ಸ್ಥಳೀಯ ಅಪ್ಲಿಕೇಶನ್ನಿಂದ ಡೇಟಾವನ್ನು ಸ್ವೀಕರಿಸುವುದನ್ನು ಮುಂದುವರಿಸಿದರೂ ದೂರದ ಪೀರ್ಗೆ ಇನ್ನಷ್ಟು ಕಳುಹಿಸಲು ಸಾಕಷ್ಟು ವಿಂಡೋವನ್ನು ಎಂದಿಗೂ ಘೋಷಿಸದಿದ್ದಾಗ ಅದು ಹ್ಯಾಂಗ್ ಆಗುತ್ತದೆ. ಪೀರ್ ನೀವು ಘೋಷಿಸಿದ ವಿಂಡೋವನ್ನು ತುಂಬುತ್ತದೆ, ACK ಮತ್ತು ವಿಂಡೋ ನವೀಕರಣಕ್ಕಾಗಿ ಕಾಯುತ್ತದೆ, ನಂತರ ನಿಲ್ಲುತ್ತದೆ. ಆಗ ನಿಮ್ಮ ಓದುಗನಿಗೆ ಮರಳಿಸಲು ಏನೂ ಇರುವುದಿಲ್ಲ, ಮತ್ತು ಅಪ್ಲಿಕೇಶನ್ ತೆರೆದ ಮತ್ತು ಮೌನ ಸಂಪರ್ಕವನ್ನು ನೋಡುತ್ತದೆ.
ಸಾಮಾನ್ಯ ಕಾರಣಗಳೆಂದರೆ ಘೋಷಿತ ವಿಂಡೋವನ್ನು ಟ್ರ್ಯಾಕ್ ಮಾಡದೆ ಸಾಕೆಟ್ಗೆ ಬರೆಯುವ ಸ್ಟ್ಯಾಕ್, ಮತ್ತು ತನ್ನ ಬಫರ್ ಖಾಲಿ ಮಾಡಿದ ನಂತರ ವಿಂಡೋ ನವೀಕರಣ ಕಳುಹಿಸಲು ಮರೆಯುವ ಸ್ಟ್ಯಾಕ್. ಹೊರಗಿನಿಂದ ಎರಡೂ ಒಂದೇ ರೀತಿ ಕಾಣುತ್ತವೆ: ಬೈಟ್ಗಳು ಹೊರಗೆ ಹೋಗುತ್ತವೆ, ಏನೂ ಮರಳಿ ಬರುವುದಿಲ್ಲ, ಯಾವುದೇ ದೋಷ ಎದ್ದುಬರುವುದಿಲ್ಲ. ಪಾರ್ಸಿಂಗ್, DNS ರೆಸಲ್ಯೂಶನ್ ಅಥವಾ ಡಿಸ್ಕ್ I/O ಮೇಲೆ ಓದು ಥ್ರೆಡ್ ಅನ್ನು ತಡೆಯುವುದು ಸಂಬಂಧವಿಲ್ಲದ ಕಾರಣಕ್ಕೆ ಅದೇ ಆಕಾರದ ಲಕ್ಷಣವನ್ನು ಉಂಟುಮಾಡುತ್ತದೆ, ಆದ್ದರಿಂದ ಹರಿವು ನಿಯಂತ್ರಣವನ್ನು ದೂಷಿಸುವ ಮೊದಲು ಥ್ರೆಡ್ ನಿಜವಾಗಿಯೂ read ಒಳಗಿದೆ ಎಂದು ಖಚಿತಪಡಿಸಿ.
ಪೀರ್ನ ಕಳುಹಿಸುವ ಸರದಿ ಮತ್ತು ಅದು ಕೊನೆಯದಾಗಿ ನೋಡಿದ ವಿಂಡೋವನ್ನು ಪರಿಶೀಲಿಸಿ. ನಿಮ್ಮ ವಿಂಡೋ ಶೂನ್ಯವಾಗಿರುವುದರಿಂದ ಪೀರ್ ಡೇಟಾವನ್ನು ಹಿಡಿದಿಟ್ಟುಕೊಂಡಿದ್ದರೆ, ಸರಿಪಡಿಸುವಿಕೆ ನಿಮ್ಮ ACK ಮಾರ್ಗದಲ್ಲಿದೆ, TUN ಓದಿನಲ್ಲಿ ಅಲ್ಲ.
ENOBUFS ಗಾತ್ರದ ಸಮಸ್ಯೆ, ಬಫರ್ ಕೊರತೆ ಅಲ್ಲ
TUN ಇಂಟರ್ಫೇಸ್ನಲ್ಲಿ ENOBUFS ಮರಳಿಸುವ ಬರವಣಿಗೆ ಸಾಮಾನ್ಯವಾಗಿ ಪ್ಯಾಕೆಟ್ ಉದ್ದವನ್ನು ನಿರಾಕರಿಸುತ್ತದೆ. ಇಂಟರ್ಫೇಸ್ಗೆ MTU ಇದೆ, ಅದಕ್ಕಿಂತ ದೊಡ್ಡ ಪ್ಯಾಕೆಟ್ ಸರದಿಗೆ ಸೇರಿಸಲಾಗದು, ಮತ್ತು ಅದೇ ಪ್ಯಾಕೆಟ್ ಅನ್ನು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿದರೆ ಪ್ರತಿ ಬಾರಿಯೂ ಅದೇ ರೀತಿ ವಿಫಲವಾಗುತ್ತದೆ. ಆ ನಿರ್ಣಾಯಕತೆಯೇ ಸುಳಿವು. ನಿಜವಾದ ಬಫರ್ ಕೊರತೆ ಒತ್ತಡ ಕಡಿಮೆಯಾದಂತೆ ಮಾಯವಾಗುತ್ತದೆ, ಆದರೆ ಗಾತ್ರದ ನಿರಾಕರಣೆ ನೀವು ಎಷ್ಟು ಕಾಯುತ್ತೀರಿ ಎಂಬುದನ್ನು ಲೆಕ್ಕಿಸುವುದಿಲ್ಲ.
TCP ಗೆ ಇದಕ್ಕಾಗಿಯೇ ಒಂದು ಕಾರ್ಯವಿಧಾನವಿದೆ, ಮತ್ತು ಅದೇ ಜನರು ಬಿಟ್ಟುಬಿಡುವ ಹಂತ: MSS ಕ್ಲ್ಯಾಂಪ್. ನೀವು ಬಳಕೆದಾರ ಸ್ಥಳದಲ್ಲಿ ಸೆಗ್ಮೆಂಟ್ಗಳನ್ನು ಸಂಶ್ಲೇಷಿಸುವಾಗ ಪೇಲೋಡ್ ಗಾತ್ರವನ್ನು ನೀವೇ ಆಯ್ಕೆ ಮಾಡುತ್ತೀರಿ, ಮತ್ತು ಅದನ್ನು ಟನೆಲ್ MTU ಬದಲು ಸ್ಥಳೀಯ ಇಂಟರ್ಫೇಸ್ MTU ನಿಂದ ತೆಗೆದುಕೊಳ್ಳುವುದು ಟನೆಲ್ ಹೊತ್ತುಕೊಳ್ಳಲಾಗದ ಸೆಗ್ಮೆಂಟ್ಗಳನ್ನು ಹೊರಡಿಸುತ್ತದೆ. ಎರಡರಲ್ಲಿ ಚಿಕ್ಕದಕ್ಕೆ ಸೀಮಿತಗೊಳಿಸಿ. ಕ್ಲ್ಯಾಂಪ್ TCP ಅನ್ನು ಮಾತ್ರ ಆವರಿಸುತ್ತದೆ, ಆದ್ದರಿಂದ ತುಂಬಾ ದೊಡ್ಡ UDP ಡೇಟಾಗ್ರಾಮ್ ಅನ್ನು ನಿಮ್ಮ ಕೋಡ್ ತುಂಡರಿಸಬೇಕು ಅಥವಾ ಬಿಡಬೇಕು.
ಡೀಬಗ್ ಮಾಡುವಾಗ ನೀವು ಬರೆಯುವ ಪ್ರತಿ ಪ್ಯಾಕೆಟ್ನ ಉದ್ದವನ್ನು ಲಾಗ್ ಮಾಡಿ. ವಿಫಲವಾಗುವ ಉದ್ದವೇ ಉತ್ತರ, ಮತ್ತು ಅದು ಪ್ರಯತ್ನಗಳ ನಡುವೆ ಬದಲಾಗುವುದಿಲ್ಲ.
ಪ್ರಕರಣಗಳನ್ನು ಬೇರ್ಪಡಿಸುವ ಮೂರು ಅಳತೆಗಳು
ಎರಡೂ ವೈಫಲ್ಯಗಳಿಗೆ ನಿಮಗೆ ಡೀಬಗರ್ ಬೇಕಿಲ್ಲ. ಸರಿಯಾದ ವಿಭಾಗಕ್ಕೆ ನಿಮ್ಮನ್ನು ನಿರ್ದೇಶಿಸಲು ಮೂರು ಅವಲೋಕನಗಳು ಸಾಕು, ಮತ್ತು ಅವು ಮರುನಿರ್ಮಾಣಕ್ಕಿಂತ ಕಡಿಮೆ ಸಮಯ ತೆಗೆದುಕೊಳ್ಳುತ್ತವೆ.
| What you see | Where to look |
|---|---|
| Reader parked, peer send queue empty, last advertised window zero | Window updates in your ACK path |
| Write fails on one length and succeeds on a smaller one | MSS clamp and tunnel MTU |
| Both directions look fine, app still sees no data | Protected socket and routing loop |
ಮೂರನೇ ಸಾಲು ಹೊಂದಿಕೆಯಾದರೆ, ಲೂಪ್ ಸ್ವತಃ ಸರಿಯಾಗಿದೆ ಮತ್ತು ಸಮಸ್ಯೆ ಎಲ್ಲಿ ಟನೆಲ್ ಅದನ್ನು ನೋಡಲಾಗದೋ ಅಲ್ಲಿದೆ: ನಿಮ್ಮ ಸ್ವಂತ VPN ಸಂಚಾರವನ್ನು ಟನೆಲ್ಗೆ ಮರಳಿ ಒಯ್ಯುವ ರಕ್ಷಿಸದ ಸಾರಿಗೆ ಸಾಕೆಟ್, ಇದು ಸಾಮಾನ್ಯವಾಗಿ ಯಶಸ್ವಿಯಾಗಿ ನಂತರ ಏನನ್ನೂ ತಲುಪಿಸದ ಸಂಪರ್ಕವಾಗಿ ಕಾಣುತ್ತದೆ.
ಎರಡೂ ಮಾರ್ಗಗಳು ಅವಲಂಬಿಸಿರುವ ಕೊಳವೆಗಳನ್ನು ಸರಿಪಡಿಸಿ
ಇಂಟರ್ಫೇಸ್ ಸರಿಯಾಗಿ ನಿರ್ಮಿಸುವವರೆಗೆ ಯಾವುದೇ ಲಕ್ಷಣವನ್ನು ಬೆನ್ನಟ್ಟುವುದು ಯೋಗ್ಯವಲ್ಲ. ಮುಖ್ಯವಾದ builder ಕರೆಗಳೆಂದರೆ ವಿಳಾಸ, ಮಾರ್ಗ, MTU ಮತ್ತು ಒಪ್ಪಿಗೆ, ಆ ಕ್ರಮದಲ್ಲಿ:
Builder()
.addAddress(10.8.0.2, 32)
.addRoute(0.0.0.0, 0)
.setMtu(1400)
.establish()MTU ಅನ್ನು ಮಾದರಿ ಬಳಸಿದ ಮೌಲ್ಯದಲ್ಲೇ ಬಿಡದೆ ಟನೆಲ್ನ ನೈಜ ಮೌಲ್ಯಕ್ಕೆ ಹೊಂದಿಸಿ. ನಂತರ ನೀವು ಬರೆಯುವ ಎಲ್ಲವೂ ಆ ಸಂಖ್ಯೆಯಿಂದ ಸೀಮಿತವಾಗಿದೆ, ಮತ್ತು ನೀವು ಹೊಂದಿಸುವ MTU ಮತ್ತು ನೀವು ಸೀಮಿತಗೊಳಿಸುವ MSS ನಡುವಿನ ವ್ಯತ್ಯಾಸವು ಸರಿಪಡಿಸುವಿಕೆಯ ನಂತರ ಬರವಣಿಗೆ ವೈಫಲ್ಯವನ್ನು ಮತ್ತೆ ತರುವ ಅತ್ಯಂತ ಸಾಮಾನ್ಯ ಮಾರ್ಗವಾಗಿದೆ. ನಂತರ VPN ಸರ್ವರ್ಗೆ ಸಂಚಾರವನ್ನು ಒಯ್ಯುವ ಸಾಕೆಟ್ ಅನ್ನು ರಕ್ಷಿಸಿ. protect ಇಲ್ಲದೆ ಆ ಪ್ಯಾಕೆಟ್ಗಳು ನಿಮ್ಮದೇ ಟನೆಲ್ಗೆ ಮರಳಿ ರೂಟ್ ಆಗುತ್ತವೆ ಮತ್ತು ಸಂಪರ್ಕ ಎಂದಿಗೂ ಪೂರ್ಣಗೊಳ್ಳುವುದಿಲ್ಲ, ಅದು ನಿಂತ ಓದಿನಂತೆ ಕಾಣುತ್ತದೆ ಆದರೆ ರೂಟಿಂಗ್ ಲೂಪ್.
ಒಪ್ಪಿಗೆಯನ್ನು ತಪ್ಪಿಸಲಾಗದು. prepare null ಮರಳಿಸದೆ ಪ್ರಾರಂಭವಾದ ಸೇವೆಗೆ ಇಂಟರ್ಫೇಸ್ ಸಿಗುವುದಿಲ್ಲ, ಮತ್ತು establish ಎಸೆಯುವ ಬದಲು null ಮರಳಿಸುತ್ತದೆ, ಆದ್ದರಿಂದ ಲೂಪ್ ಪ್ರಾರಂಭಿಸುವ ಮೊದಲು ಡಿಸ್ಕ್ರಿಪ್ಟರ್ ಪರಿಶೀಲಿಸಿ. VpnService ಉಲ್ಲೇಖ ಮಾದರಿಯನ್ನು ನಕಲಿಸುವ ಬದಲು builder ಒಪ್ಪಂದವನ್ನು ದೃಢೀಕರಿಸುವ ಸ್ಥಳ.
ಒಂದೊಂದಾಗಿ ಒಂದು ದಿಕ್ಕನ್ನು ಪರಿಶೀಲಿಸಿ
TCP ಮುಟ್ಟುವ ಮೊದಲು ಟನೆಲ್ ಮೂಲಕ UDP ಪ್ರತಿಧ್ವನಿ ಕಳುಹಿಸಿ ಪ್ಯಾಕೆಟ್ ಉದ್ದಗಳನ್ನು ಗಮನಿಸಿ. ನಂತರ ಹ್ಯಾಂಡ್ಶೇಕ್ ತೆರೆದು ನೀವು ಲೆಕ್ಕಹಾಕಿದ MSS ಗಿಂತ ಸೆಗ್ಮೆಂಟ್ಗಳು ಕಡಿಮೆ ಇರುವುದನ್ನು ದೃಢೀಕರಿಸಿ. ಸಂಪರ್ಕಗಳಿಗಿಂತ ಪ್ಯಾಕೆಟ್ಗಳನ್ನು ಎಣಿಸಿ, ಇದರಿಂದ ನಿಲುಗಡೆ ನೇತಾಡುವ ಸಾಕೆಟ್ ಬದಲು ಕೌಂಟರ್ನಲ್ಲಿ ಅಂತರವಾಗಿ ಕಾಣುತ್ತದೆ. ಬರವಣಿಗೆಗಳ ಸುರಿಮಳೆಯ ನಂತರ ಓದು ನಿಂತರೆ, ವಿಂಡೋ ಶಂಕಿತ; ಬರವಣಿಗೆಗಳು ತಕ್ಷಣ ವಿಫಲವಾದರೆ, ಉದ್ದ.
ನಂತರ ಸಾಧನವನ್ನು ಮರುಬೂಟ್ ಮಾಡಿ ಒಮ್ಮೆ ಪುನರಾವರ್ತಿಸಿ, ಏಕೆಂದರೆ ಮೊದಲ ನೆಟ್ವರ್ಕ್ ಬದಲಾವಣೆಯವರೆಗೆ ಮಾತ್ರ ಕೆಲಸ ಮಾಡುವ VpnService ಹರಿವು ನಿಯಂತ್ರಣದ್ದಲ್ಲ, ರೂಟಿಂಗ್ ಸಮಸ್ಯೆ.