В основном я создаю приложение VPN, для подключения которого просто требуются имя пользователя и пароль для адреса сервера, поэтому, когда я помещаю учетные данные непосредственно в add VPN из настроек, он работает нормально, но при подключении из приложения он не работает.
Это мое основное занятие, в которое я поместил все детали напрямую.
public class MainActivity extends AppCompatActivity {
private static final String KEY_PASSWORD = "an4d7bm";
private static final String KEY_USERNAME = "vpnbook";
@SuppressLint("WrongViewCast")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btConnect = findViewById(R.id.connect);
btConnect.setOnClickListener(new View.OnClickListener() {
@SuppressLint("WrongViewCast")
@Override
public void onClick(View v) {
Intent intent = VpnService.prepare(getApplicationContext());
if (intent != null) {
startActivityForResult(intent, 0);
} else {
onActivityResult(0, RESULT_OK, null);
}
}
});
}
@SuppressLint("MissingSuperCall")
public void onActivityResult(int requestCode, int resultCode, Intent data) {
Intent intent = new Intent(this, Client.class);
EditText username = findViewById(R.id.username);
EditText pw = findViewById(R.id.password);
intent.putExtra(MainActivity.KEY_USERNAME, "vpnbook");
intent.putExtra(MainActivity.KEY_PASSWORD, "an4d7bm");
startService(intent);
}}
VpnService
public class Client extends VpnService{
private static final String TAG = "VPN";
private Thread mThread;
private ParcelFileDescriptor mInterface;
//a. Configure a builder for the interface.
Builder builder = new Builder();
private long IDLE_INTERVAL_MS = 100;
private long KEEPALIVE_INTERVAL_MS = 100;
private long RECEIVE_TIMEOUT_MS = 1000;
// Services interface
@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
String username = "vpnbook";
String password = "an4d7bm";
mThread = new Thread(() -> {
try {
mInterface = builder.setSession("MyVPNService")
.addAddress("94.23.57.8", 24)
.establish();
FileInputStream in = new FileInputStream(
mInterface.getFileDescriptor());
FileOutputStream out = new FileOutputStream(
mInterface.getFileDescriptor());
DatagramChannel tunnel = DatagramChannel.open();
tunnel.socket().bind(new InetSocketAddress(0));
int port = tunnel.socket().getLocalPort();
Log.d("VPNservice", "2 " + (tunnel != null));
Log.d("VPNservice", "3 " + tunnel.connect(new InetSocketAddress(port)));
tunnel.configureBlocking(false);
protect(tunnel.socket());
ByteBuffer packet = ByteBuffer.allocate(Short.MAX_VALUE);
long lastReceiveTime = System.currentTimeMillis();
long lastSendTime = System.currentTimeMillis();
while (true) {
boolean idle = true;
int length = in.read(packet.array());
if (length > 0) {
packet.limit(length);
tunnel.write(packet);
packet.clear();
idle = false;
lastReceiveTime = System.currentTimeMillis();
Log.d("Log", "Write package");
}
length = tunnel.read(packet);
if (length > 0) {
if (packet.get(0) != 0){
out.write(packet.array(), 0, length);
}
packet.clear();
idle = false;
lastSendTime = System.currentTimeMillis();
}
if (idle) {
Thread.sleep(IDLE_INTERVAL_MS);
final long timeNow = System.currentTimeMillis();
if (lastSendTime + KEEPALIVE_INTERVAL_MS <= timeNow) {
packet.put((byte) 0).limit(1);
for (int i = 0; i < 3; ++i) {
packet.position(0);
tunnel.write(packet);
}
packet.clear();
lastSendTime = timeNow;
} else if (lastReceiveTime + RECEIVE_TIMEOUT_MS <= timeNow) {
throw new IllegalStateException("Timed out");
}
}
}
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
} finally {
try {
if (mInterface != null) {
mInterface.close();
mInterface = null;
}
} catch (Exception e) {
Log.d("Erro: ", e.getMessage());
}
}
}, "MyVpnRunnable");
mThread.start();
return START_STICKY;
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
if (mThread != null) {
mThread.interrupt();
}
super.onDestroy();
}
}