Android 'ਤੇ VPN ਖੋਜਣਾ: tun0 ਅਤੇ ping ਕਿਉਂ ਗੁੰਮਰਾਹ ਕਰਦੇ ਹਨ
ਇੰਟਰਫੇਸ ਦਾ ਨਾਮ ਇੱਕ ਰੀਤ ਹੈ; ping ਸਾਬਤ ਕਰਦਾ ਹੈ ਕਿ ਇੱਕ ਹੋਸਟ ਪਹੁੰਚਯੋਗ ਸੀ। NetworkCapabilities ਨੂੰ ਪੁੱਛੋ ਕਿ ਨੈੱਟਵਰਕ ਕੀ ਐਲਾਨਦਾ ਹੈ, ਫਿਰ ਕਾਲਬੈਕਾਂ 'ਤੇ ਪ੍ਰਤੀਕਿਰਿਆ ਦਿਓ।
ਬਹੁਤੀਆਂ Android ਐਪਾਂ VPN ਖੋਜਣ ਲਈ ਜੋ ਜਾਂਚ ਵਰਤਦੀਆਂ ਹਨ ਉਹ ਇੰਟਰਫੇਸ ਦਾ ਨਾਮ ਹੈ, ਅਤੇ ਇਹ ਕਦੇ VPN ਜਾਂਚ ਨਹੀਂ ਸੀ। ਇਹ ਦੱਸਦੀ ਹੈ ਕਿ ਡਿਵੈਲਪਰ ਦੀ ਉਮੀਦ ਵਾਲੀ ਸਤਰ ਨਾਲ ਕੋਈ ਇੰਟਰਫੇਸ ਮੌਜੂਦ ਹੈ, ਜਿਸਦਾ ਇੱਕ ਡਿਵਾਈਸ 'ਤੇ ਅਰਥ OpenVPN ਹੈ ਅਤੇ ਦੂਜੇ 'ਤੇ ਪੂਰੀ ਤਰ੍ਹਾਂ ਅਸੰਬੰਧਿਤ ਕੁਝ। ping ਇਸੇ ਤਰ੍ਹਾਂ ਦਾ ਸਬੂਤ ਹੈ: ਇਹ ਸਾਬਤ ਕਰਦਾ ਹੈ ਕਿ ਇੱਕ ਮੰਜ਼ਿਲ ਨੇ ਜਵਾਬ ਦਿੱਤਾ, ਇਹ ਨਹੀਂ ਕਿ ਟਨਲ ਨੇ ਪੈਕਟ ਢੋਇਆ। ਪਲੇਟਫਾਰਮ ਅਸਲ ਵਿੱਚ ਜੋ ਪ੍ਰਗਟ ਕਰਦਾ ਹੈ ਉਹ ਨੈੱਟਵਰਕਾਂ ਦਾ ਸਮੂਹ ਅਤੇ ਹਰੇਕ ਵੱਲੋਂ ਐਲਾਨੇ ਟਰਾਂਸਪੋਰਟ ਹਨ, ਅਤੇ ਇਹ ਵੱਖਰੇ ਜਵਾਬ ਵਾਲਾ ਵੱਖਰਾ ਸਵਾਲ ਹੈ।
ਭਰਮ: ਜੇ tun0 ਹੈ ਤਾਂ VPN ਚਾਲੂ ਹੈ
Android VPN ਐਪਾਂ VpnService ਦੀਆਂ ਲਾਗੂਆਂ ਹਨ ਜੋ ਸਿਸਟਮ ਨੂੰ tun ਫਾਈਲ ਡਿਸਕ੍ਰਿਪਟਰ ਦਿੰਦੀਆਂ ਹਨ। ਇੰਟਰਫੇਸ ਦਾ ਨਾਮ ਇਸਨੂੰ ਬਣਾਉਣ ਵਾਲੇ ਤੋਂ ਆਉਂਦਾ ਹੈ: OpenVPN ਆਮ ਤੌਰ 'ਤੇ tun0 ਬਣਾਉਂਦਾ ਹੈ, PPTP ਅਤੇ L2TP ppp0 ਬਣਾਉਂਦੇ ਹਨ, WireGuard ਆਪਣੇ ਇੰਟਰਫੇਸ ਦਾ ਨਾਮ ਟਨਲ ਪਿੱਛੋਂ ਰੱਖਦਾ ਹੈ, ਅਤੇ IPsec ਟਨਲ ਕੋਈ ਰਵਾਇਤੀ ਨਾਮ ਹੀ ਨਹੀਂ ਦਿਖਾ ਸਕਦਾ। ਇਸ ਲਈ /proc/net/dev ਪੜ੍ਹਨਾ ਜਾਂ NetworkInterface ਵਸਤੂਆਂ ਗਿਣਨਾ ਤੱਥ ਨਹੀਂ, ਰੀਤ ਲੱਭਦਾ ਹੈ।
ਗਲਤੀ ਦੀਆਂ ਦੋਵੇਂ ਦਿਸ਼ਾਵਾਂ ਜੀਵਤ ਹਨ। ਡਿਵਾਈਸ ਵਿੱਚ ਵਰਤੋਂਕਾਰ ਦੇ VPN ਨਾਲ ਕੋਈ ਸੰਬੰਧ ਨਾ ਰੱਖਣ ਵਾਲੇ ਸਥਾਨਕ ਟਨਲ ਲਈ tun0 ਹੋ ਸਕਦਾ ਹੈ, ਅਤੇ ਪੂਰੀ ਤਰ੍ਹਾਂ ਸਿਹਤਮੰਦ WireGuard ਟਨਲ ਸਿਰਫ਼ tun0 ਸਤਰ ਜਾਣਨ ਵਾਲੀ ਜਾਂਚ ਲਈ ਅਦਿੱਖ ਹੋ ਸਕਦਾ ਹੈ। ਇੱਕੋ ਫੰਕਸ਼ਨ ਵਿੱਚ ਝੂਠੇ ਸਕਾਰਾਤਮਕ ਅਤੇ ਝੂਠੇ ਨਕਾਰਾਤਮਕ ਨਤੀਜੇ ਇਸਨੂੰ ਨਿਦਾਨ ਵਜੋਂ ਬੇਕਾਰ ਬਣਾਉਂਦੇ ਹਨ, ਕਿਉਂਕਿ «ਕੋਈ VPN ਨਹੀਂ ਮਿਲਿਆ» ਕਹਿਣ ਵਾਲੀ ਸਹਾਇਤਾ ਟਿਕਟ 'ਤੇ ਕਿਸੇ ਵੀ ਦਿਸ਼ਾ ਵਿੱਚ ਭਰੋਸਾ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।
ਪਹੁੰਚ ਵੀ ਤੰਗ ਹੋਈ ਹੈ। ਨਵੇਂ Android ਸੰਸਕਰਣ ਸੀਮਤ ਕਰਦੇ ਹਨ ਕਿ ਆਮ ਐਪ /proc ਤੋਂ ਕੀ ਪੜ੍ਹ ਸਕਦੀ ਹੈ, ਇਸ ਲਈ Android 8 'ਤੇ ਕੰਮ ਕਰਨ ਵਾਲੀ ਨਾਮ-ਆਧਾਰਿਤ ਜਾਂਚ ਕਿਸੇ ਕੋਡ ਬਦਲਾਅ ਤੋਂ ਬਿਨਾਂ ਬਾਅਦ ਵਾਲੇ ਡਿਵਾਈਸ 'ਤੇ ਖਾਲੀ ਸੂਚੀ ਵਾਪਸ ਕਰ ਸਕਦੀ ਹੈ। ਜਦੋਂ ਜਾਂਚ ਚੁੱਪਚਾਪ ਖੁੱਲ੍ਹੇ ਪਾਸੇ ਫੇਲ੍ਹ ਹੁੰਦੀ ਹੈ, ਐਪ ਸਿੱਟਾ ਕੱਢਦੀ ਹੈ ਕਿ ਜਿਸ ਹਾਰਡਵੇਅਰ 'ਤੇ ਟਨਲ ਠੀਕ ਹੈ ਉੱਥੇ VPN ਨਹੀਂ ਹੈ।
ਭਰਮ: ਸਫਲ ping ਦਾ ਮਤਲਬ ਟਨਲ ਟ੍ਰੈਫਿਕ ਢੋ ਰਿਹਾ ਹੈ
ਅੰਦਰੂਨੀ ਹੋਸਟ ਨੂੰ ping ਤਦ ਸਫਲ ਹੁੰਦਾ ਹੈ ਜਦੋਂ ਉਸ ਹੋਸਟ ਤੱਕ ਰਸਤਾ ਮੌਜੂਦ ਹੋਵੇ। ਵੰਡੇ ਟਨਲਿੰਗ ਵਿੱਚ ਹੋਸਟ Wi-Fi ਰਾਹੀਂ ਪਹੁੰਚਯੋਗ ਹੋ ਸਕਦਾ ਹੈ ਜਦੋਂ ਟਨਲ ਚਾਲੂ ਹੈ ਅਤੇ ਪੂਰੀ ਤਰ੍ਹਾਂ ਕੁਝ ਹੋਰ ਕਰ ਰਿਹਾ ਹੈ। ਪ੍ਰਤੀ-ਐਪ VPN ਵਿੱਚ ping ਕਰਨ ਵਾਲੀ ਐਪ ਟਨਲ ਤੋਂ ਬਾਹਰ ਰੱਖੀ ਜਾ ਸਕਦੀ ਹੈ, ਇਸ ਲਈ ICMP ਗੂੰਜ ਇਸਦੇ ਬਾਹਰ ਜਾਂਦੀ ਹੈ ਅਤੇ ਵਾਪਸ ਆਉਂਦੀ ਹੈ, ਜੋ ਜਾਂਚ ਦੀ ਧਾਰਨਾ ਦੇ ਉਲਟ ਸਾਬਤ ਕਰਦੀ ਹੈ।
ICMP ਅਤੇ TCP ਵੀ ਵੱਖਰੇ ਤੌਰ 'ਤੇ ਫਿਲਟਰ ਹੁੰਦੇ ਹਨ। ਜੋ ਟਨਲ ਗੂੰਜ ਬੇਨਤੀਆਂ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ ਪਰ ਸੇਵਾ ਲਈ ਲੋੜੀਂਦਾ TCP ਪੋਰਟ ਛੱਡ ਦਿੰਦਾ ਹੈ, ਉਹ ping ਟੈਸਟ ਪਾਸ ਕਰੇਗਾ ਅਤੇ ਐਪ ਵਿੱਚ ਫੇਲ੍ਹ ਹੋਵੇਗਾ, ਅਤੇ ਇਹ ਡਿਵਾਈਸ ਦੀ ਵਿਸ਼ੇਸ਼ਤਾ ਨਹੀਂ ਬਲਕਿ ਪਾਰਲੇ ਪਾਸੇ ਦਾ ਫਾਇਰਵਾਲ ਨਿਯਮ ਹੈ। ਸਫਲ ping ਦਾ ਇੱਕੋ ਇੱਕ ਇਮਾਨਦਾਰ ਪਾਠ ਇਹ ਹੈ ਕਿ ਇਸ ਮੰਜ਼ਿਲ ਨੇ ਇਸ ਪਲ ਇਸ ਪ੍ਰੋਟੋਕੋਲ ਨੂੰ ਜਵਾਬ ਦਿੱਤਾ।
ਪਲੇਟਫਾਰਮ ਅਸਲ ਵਿੱਚ ਕੀ ਰਿਪੋਰਟ ਕਰਦਾ ਹੈ
API 21 ਤੋਂ ConnectivityManager.getAllNetworks() ਸਿਸਟਮ ਨੂੰ ਪਤਾ ਹਰ ਨੈੱਟਵਰਕ ਵਾਪਸ ਕਰਦਾ ਹੈ, ਅਤੇ getNetworkCapabilities(network) ਦੱਸਦਾ ਹੈ ਕਿ ਉਹ ਨੈੱਟਵਰਕ ਕੀ ਐਲਾਨਦਾ ਹੈ। VPN ਨੈੱਟਵਰਕ TRANSPORT_VPN ਰੱਖਦਾ ਹੈ। ਸਾਰੇ ਨੈੱਟਵਰਕਾਂ 'ਤੇ ਲੂਪ ਕਰਨਾ ਇੱਕ ਸਵਾਲ ਦਾ ਜਵਾਬ ਦਿੰਦਾ ਹੈ: ਕੀ ਇਸ ਡਿਵਾਈਸ 'ਤੇ ਹੁਣ ਕੋਈ VPN ਚਾਲੂ ਹੈ?
ਦੂਜਾ, ਹੋਰ ਤੰਗ ਸਵਾਲ ਵੱਖਰੀ ਕਾਲ ਮੰਗਦਾ ਹੈ। getActiveNetwork() ਉਹ ਨੈੱਟਵਰਕ ਵਾਪਸ ਕਰਦਾ ਹੈ ਜੋ ਐਪ ਦਾ ਟ੍ਰੈਫਿਕ ਹੁਣ ਵਰਤੇਗਾ, ਅਤੇ ਉਸ 'ਤੇ ਉਹੀ ਸਮਰੱਥਾ ਜਾਂਚਣਾ ਜਵਾਬ ਦਿੰਦਾ ਹੈ: ਕੀ ਮੇਰਾ ਟ੍ਰੈਫਿਕ VPN ਰਾਹੀਂ ਜਾਵੇਗਾ? ਦੋਵੇਂ ਅਸਹਿਮਤ ਹੋ ਸਕਦੇ ਹਨ, ਅਤੇ ਇਹ ਅਸਹਿਮਤੀ ਜਾਣਕਾਰੀਪੂਰਨ ਹੈ। ਚਾਲੂ ਪਰ ਮੌਜੂਦਾ ਨਾ ਹੋਣ ਵਾਲਾ VPN ਪ੍ਰਤੀ-ਐਪ ਰਾਊਟਿੰਗ ਜਾਂ ਵੰਡੇ-ਟਨਲ ਸੰਰਚਨਾ ਵੱਲ ਇਸ਼ਾਰਾ ਕਰਦਾ ਹੈ, ਗੁੰਮ ਟਨਲ ਵੱਲ ਨਹੀਂ।
Network active = cm.getActiveNetwork();
NetworkCapabilities caps = cm.getNetworkCapabilities(active);
boolean viaVpn = caps != null
&& caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
ਦੋਵੇਂ ਕਾਲਾਂ ਦੀ ਰੱਖਿਆ ਕਰੋ। ਸੂਚੀਬੱਧ ਕਰਨ ਅਤੇ ਪੁੱਛਣ ਵਿਚਕਾਰ ਗਾਇਬ ਹੋਏ ਨੈੱਟਵਰਕ ਲਈ ਸਮਰੱਥਾਵਾਂ null ਹੋ ਸਕਦੀਆਂ ਹਨ, ਅਤੇ ਹੈਂਡਓਵਰ ਦੌਰਾਨ ਸਰਗਰਮ ਨੈੱਟਵਰਕ null ਹੋ ਸਕਦਾ ਹੈ। NET_CAPABILITY_NOT_VPN ਉਲਟ ਦਿਸ਼ਾ ਵਿੱਚ ਲਾਹੇਵੰਦ ਹੈ, ਇਹ ਪੱਕਾ ਕਰਨ ਲਈ ਕਿ ਨੈੱਟਵਰਕ ਨਿਸ਼ਚਤ ਤੌਰ 'ਤੇ ਟਨਲ ਨਹੀਂ ਹੈ, ਨਾ ਕਿ ਸਿਰਫ਼ ਇਸ ਵਿੱਚ VPN ਟਰਾਂਸਪੋਰਟ ਝੰਡਾ ਨਹੀਂ ਹੈ।
NetworkInfo API ਨਾਲ ਉਹੀ ਭਰਮ ਸੀ
NetworkInfo ਨਾਲ ConnectivityManager.TYPE_VPN ਇਸ ਜਾਂਚ ਦੀ ਦੂਜੀ ਪੀੜ੍ਹੀ ਹੈ, ਅਤੇ ਇਹ ਕਿਸੇ ਕਾਰਨ ਕਰਕੇ ਅਪ੍ਰਚਲਿਤ ਹੈ। ਆਧੁਨਿਕ ਸੰਸਕਰਣਾਂ ਵਿੱਚ ਟਨਲ ਜੁੜਿਆ ਹੋਣ 'ਤੇ ਵੀ VPN ਲਈ ਵਾਪਸ ਕੀਤੀ ਵਸਤੂ null ਹੋ ਸਕਦੀ ਹੈ, ਇਸ ਲਈ null ਨੂੰ «VPN ਨਹੀਂ» ਮੰਨਣ ਵਾਲਾ ਕੋਡ ਉਨ੍ਹਾਂ ਡਿਵਾਈਸਾਂ 'ਤੇ ਚੁੱਪਚਾਪ ਝੂਠਾ ਨਕਾਰਾਤਮਕ ਦੱਸਦਾ ਹੈ ਜਿੱਥੇ ਜਵਾਬ ਸਭ ਤੋਂ ਵੱਧ ਮਾਇਨੇ ਰੱਖਦਾ ਹੈ।
ਆਮ ਤੌਰ 'ਤੇ ਇਸਦੇ ਨਾਲ ਆਉਣ ਵਾਲਾ ਪ੍ਰਸਾਰਣ ਵੀ ਬਿਹਤਰ ਨਹੀਂ। CONNECTIVITY_CHANGE ਦਾ VPN ਤਬਦੀਲੀਆਂ ਖੁੰਝਾਉਣ ਦਾ ਦਸਤਾਵੇਜ਼ੀ ਇਤਿਹਾਸ ਹੈ, ਜਿਸ ਵਿੱਚ ਉਹ ਬਿਲਡ ਵੀ ਹਨ ਜਿੱਥੇ ਇਹ ਹਰ ਨੈੱਟਵਰਕ ਬਦਲਾਅ 'ਤੇ ਨਹੀਂ ਬਲਕਿ ਸਿਰਫ਼ VPN ਜੁੜਨ ਜਾਂ ਟੁੱਟਣ 'ਤੇ ਚੱਲਦਾ ਸੀ। ਇਸ 'ਤੇ ਬਣਿਆ ਸਰੋਤਾ ਅਜਿਹਾ ਸਥਿਤੀ ਚਰ ਬਣਾਉਂਦਾ ਹੈ ਜੋ ਅਗਲੇ ਪੂਰੇ ਮੁੜ-ਜੁੜਾਅ ਤੱਕ ਪਲੇਟਫਾਰਮ ਦੇ ਦ੍ਰਿਸ਼ ਤੋਂ ਦੂਰ ਜਾਂਦਾ ਹੈ।
ਪੋਲਿੰਗ ਦੀ ਬਜਾਏ ਕਾਲਬੈਕਾਂ 'ਤੇ ਪ੍ਰਤੀਕਿਰਿਆ ਦਿਓ
ਅਜਿਹੀ NetworkRequest ਦਰਜ ਕਰੋ ਜੋ TRANSPORT_VPN ਮੰਗਦੀ ਹੈ ਅਤੇ NET_CAPABILITY_NOT_VPN ਹਟਾਉਂਦੀ ਹੈ, ਫਿਰ ਉਸ ਬੇਨਤੀ ਨਾਲ registerNetworkCallback ਕਾਲ ਕਰੋ। ਫਿਰ onAvailable ਅਤੇ onLost ਦੱਸਦੇ ਹਨ ਕਿ ਐਲਾਨ ਕਦੋਂ ਬਦਲਦਾ ਹੈ, ਅਤੇ ਇਹੀ ਉਹ ਘਟਨਾ ਹੈ ਜੋ ਤੁਹਾਡੇ ਲਈ ਸੱਚਮੁੱਚ ਮਾਇਨੇ ਰੱਖਦੀ ਹੈ। ਕੰਪੋਨੈਂਟ ਰੁਕਣ 'ਤੇ ਕਾਲਬੈਕ ਦੀ ਰਜਿਸਟਰੇਸ਼ਨ ਰੱਦ ਕਰੋ, ਨਹੀਂ ਤਾਂ ਐਪ ਮਰੀ ਸਕਰੀਨ ਦਾ ਹਵਾਲਾ ਰੱਖਦੀ ਹੈ ਅਤੇ ਕਾਲਬੈਕ ਚੱਲਦਾ ਰਹਿੰਦਾ ਹੈ।
NetworkRequest req = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_VPN)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
.build();
cm.registerNetworkCallback(req, callback);
ਇਸ ਲਈ ACCESS_NETWORK_STATE ਲੋੜੀਂਦਾ ਹੈ, ਜੋ ਇੱਕ ਆਮ ਇਜਾਜ਼ਤ ਹੈ: root ਨਹੀਂ, ਵਰਤੋਂਕਾਰ ਸਹਿਮਤੀ ਸੰਵਾਦ ਨਹੀਂ, VPN ਇਜਾਜ਼ਤ ਨਹੀਂ। ਟਾਈਮਰ 'ਤੇ ਪੋਲਿੰਗ ਉਹ ਵਿਕਲਪ ਹੈ ਜਿਸ ਵੱਲ ਲੋਕ ਮੁੜਦੇ ਹਨ, ਅਤੇ ਇਹ ਬੈਟਰੀ ਸਾੜਦਾ ਹੈ ਅਤੇ ਫਿਰ ਵੀ ਅੰਤਰਾਲ ਤੋਂ ਛੋਟਾ ਤਬਦੀਲੀ ਖੁੰਝਾ ਦਿੰਦਾ ਹੈ, ਜੋ ਠੀਕ ਉਹੀ ਤਬਦੀਲੀ ਹੈ ਜਿਸਦੀ ਵਰਤੋਂਕਾਰ ਸ਼ਿਕਾਇਤ ਕਰਦਾ ਹੈ।
ਜਵਾਬ ਹਾਲੇ ਵੀ ਤੁਹਾਨੂੰ ਕੀ ਨਹੀਂ ਦੱਸ ਸਕਦਾ
ਇਹਨਾਂ API ਵਿੱਚੋਂ ਕੋਈ ਵੀ ਇਹ ਨਹੀਂ ਦੱਸਦਾ ਕਿ ਟਨਲ ਸਿਹਤਮੰਦ ਹੈ, ਕਿਹੜੇ ਸਰਵਰ 'ਤੇ ਖ਼ਤਮ ਹੁੰਦਾ ਹੈ, ਜਾਂ ਕਿਸੇ ਖਾਸ ਐਪ ਦਾ ਟ੍ਰੈਫਿਕ ਇਸਦੇ ਅੰਦਰ ਹੈ। VPN ਨੈੱਟਵਰਕ ਲਾਹੇਵੰਦ ਰਸਤਿਆਂ ਤੋਂ ਬਿਨਾਂ ਵੀ ਮੌਜੂਦ ਹੋ ਸਕਦਾ ਹੈ, ਅਤੇ ਪ੍ਰਤੀ-ਐਪ ਟਨਲ ਸਵਾਲ ਪੁੱਛਣ ਵਾਲੀ ਐਪ ਨੂੰ ਬਾਹਰ ਰੱਖ ਸਕਦਾ ਹੈ।
ਇਸ ਲਈ ਦਰਜ ਕਰੋ ਕਿ ਜਾਂਚ ਨੇ ਕੀ ਦੇਖਿਆ, ਸਿਰਫ਼ ਬੂਲੀਅਨ ਨਹੀਂ। ਨੈੱਟਵਰਕ ਪਛਾਣਕਰਤਾ, ਐਲਾਨੇ ਟਰਾਂਸਪੋਰਟ ਅਤੇ ਇਹ ਕਿ ਉਹ ਨੈੱਟਵਰਕ ਸਰਗਰਮ ਸੀ, ਲੌਗ ਕਰੋ। «ਕੋਈ VPN ਨਹੀਂ ਮਿਲਿਆ» ਕਹਿਣ ਵਾਲੀ ਰਿਪੋਰਟ ਬੇਕਾਰ ਹੈ, ਜਦਕਿ ਇਹ ਕਹਿਣ ਵਾਲੀ ਰਿਪੋਰਟ ਕਿ ਕਿਸੇ ਨੈੱਟਵਰਕ ਨੇ TRANSPORT_VPN ਐਲਾਨਿਆ ਪਰ getActiveNetwork() ਨੇ Wi-Fi ਵਾਪਸ ਕੀਤਾ, ਸਿੱਧਾ ਰਾਊਟਿੰਗ ਜਾਂ ਬਾਹਰ ਕੱਢਣ ਸੂਚੀ ਵੱਲ ਇਸ਼ਾਰਾ ਕਰਦੀ ਹੈ, ਅਤੇ ਇਹ ਅਜਿਹਾ ਸੁਧਾਰ ਹੈ ਜਿਸ 'ਤੇ ਕੋਈ ਕੰਮ ਕਰ ਸਕਦਾ ਹੈ।