Я пытаюсь создать приложение VPN android с использованием VPNService для какого-либо поставщика услуг VPN. При попытке чтения данных столкнулся с проблемой ниже:
Не удалось прочитать данные с адреса сокета "xxx.xxx.xxx.xx". Может кто-нибудь помочь мне понять, что я здесь пропустил?
//Able to establish an Inteface like below
ParcelFileDescriptor mInterface = builder
.addAddress("10.50.0.3", 32)
.addDnsServer("8.8.8.8")
.addRoute("0.0.0.0", 0)
.establish();
// Создан туннель, как показано ниже (я полагаю, это равноправно)
DatagramChannel tunnel = DatagramChannel.open();
tunnel.connect(new InetSocketAddress("3.101.128.28", 443));
tunnel.configureBlocking(false);
protect(tunnel.socket());
Кроме того, попытался записать общий ключ publi c в пакеты для отправки в туннель, как показано ниже, но это тоже не помогло работа.
ByteBuffer packet = ByteBuffer.allocate(1024);
packet.put((byte) 0).put("PrtBg/5jooxYciQgi1XCzyXXXXXXXIzqmKQRtPSc=".getBytes()).flip();
packet.position(0);
tunnel.write(packet);
Тем не менее, чтение данных из туннеля всегда возвращает ноль.
int length = tunnel.read(packet);
Ниже приведен класс обслуживания Complete:
public class MyVPNService extends VpnService {
private Thread mThread;
private ParcelFileDescriptor mInterface;
Builder builder = new Builder();
private static final int MAX_PACKET_SIZE = Short.MAX_VALUE;
private static final long RECEIVE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(20);
private static final long IDLE_INTERVAL_MS = TimeUnit.MILLISECONDS.toMillis(100);
private static final long KEEPALIVE_INTERVAL_MS = TimeUnit.SECONDS.toMillis(15);
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Start a new session by creating a new thread.
mThread = new Thread(new Runnable() {
@Override
public void run() {
try {
// -----------------Interface----------------
//Configure the TUN and get the interface.
mInterface = builder
.addAddress("10.50.0.3", 32)
.addDnsServer("8.8.8.8")
.addRoute("0.0.0.0", 0)
.establish();
//b. Packets to be sent are queued in this input stream.
FileInputStream in = new FileInputStream(
mInterface.getFileDescriptor());
//b. Packets received need to be written to this output stream.
FileOutputStream out = new FileOutputStream(
mInterface.getFileDescriptor());
//-------------------Peer-----------------------
//c. The UDP channel can be used to pass/get ip package to/from server
DatagramChannel tunnel = DatagramChannel.open();
tunnel.connect(new InetSocketAddress("3.101.128.28", 443));
// For simplicity, we use the same thread for both reading and
// writing. Here we put the tunnel into non-blocking mode.
tunnel.configureBlocking(false);
//Protect this socket, so package send by it will not be feedback to the vpn service.
protect(tunnel.socket());
//Allocate the buffer for a single packet.
ByteBuffer packet = ByteBuffer.allocate(MAX_PACKET_SIZE);
packet.put((byte) 0).put("PrtBg/5jooxYciQgi1XCzyGhhZtQejcjIzqmKQRtPSc=".getBytes()).flip();
packet.position(0);
//Timeouts:
// - when data has not been sent in a while, send empty keepalive messages.
// - when data has not been received in a while, assume the connection is broken.
long lastSendTime = System.currentTimeMillis();
long lastReceiveTime = System.currentTimeMillis();
// We keep forwarding packets till something goes wrong.
while (true) {
// Assume that we did not make any progress in this iteration.
boolean idle = true;
// Read the outgoing packet from the input stream.
int length = in.read(packet.array());
if (length > 0) {
// Write the outgoing packet to the tunnel.
packet.limit(length);
tunnel.write(packet);
packet.clear();
// There might be more outgoing packets.
idle = false;
lastReceiveTime = System.currentTimeMillis();
}
// Read the incoming packet from the tunnel.
**length = tunnel.read(packet); // This length is always zero**
if (length > 0) {
// Ignore control messages, which start with zero.
if (packet.get(0) != 0) {
// Write the incoming packet to the output stream.
out.write(packet.array(), 0, length);
}
packet.clear();
// There might be more incoming packets.
idle = false;
lastSendTime = System.currentTimeMillis();
}
// If we are idle or waiting for the network, sleep for a
// fraction of time to avoid busy looping.
if (idle) {
Thread.sleep(IDLE_INTERVAL_MS);
final long timeNow = System.currentTimeMillis();
if (lastSendTime + KEEPALIVE_INTERVAL_MS <= timeNow) {
// We are receiving for a long time but not sending.
// Send empty control messages.
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) {
// We are sending for a long time but not receiving.
throw new IllegalStateException("Timed out");
}
}
}
} catch (Exception e) {
// Catch any exception
e.printStackTrace();
System.out.println(">>Rock Exception ::" + e.getMessage());
} finally {
try {
if (mInterface != null) {
mInterface.close();
mInterface = null;
}
} catch (Exception e) {
System.out.println(">>Rock Exception22 ::" + e.getMessage());
}
}
}
}, "MyVpnRunnable");
//start the service
mThread.start();
return START_STICKY;
}
@Override
public void onDestroy() {
System.out.println(">>Rock onDestroy ::");
// TODO Auto-generated method stub
if (mThread != null) {
mThread.interrupt();
}
super.onDestroy();
}
}