I'm trying to use the Android4.x VPN Service to establish a VPN tunnel with inner Ethernet server.the IP address is a globle ip on Internet.Now here is the problems:
1.I use TCP dump to catch packets, after a VPN Service.build established, none of tcp packets can be transport in the tunnel, which was connected to server before.
2.after the build established, I get a fileDescriptor, it cannot write any bytes(EINVAL error), and cannot read any bytes(length = 0).
3.I use the socket tunnel to communicate to the server and send PPTP packet, after start-control-request, outgoing-call-request, the server returned correct information and then transport configure information through PPP LCP protocol. However, I don't know what to do next, how to get the PPP LCP packet?It's not from socket, and file Descriptor can't read or write anything.
Please help, thanks everyone!
private static ParcelFileDescriptor tunPFD;
private boolean run(InetSocketAddress server) throws Exception {
SocketChannel tunnel = null;
boolean connected = false;
try {
// Create a DatagramChannel as the VPN tunnel.
tunnel = SocketChannel.open();
// Protect the tunnel before connecting to avoid loopback.
if (!protect(tunnel.socket())) {
// throw new IllegalStateException("Cannot protect the tunnel");
System.out.println("can't protected");
}
// Connect to the server.
tunnel.connect(server);
System.out.println("connected");
// For simplicity, we use the same thread for both reading and
// writing. Here we put the tunnel into non-blocking mode.
tunnel.configureBlocking(true);
System.out.println("PFD success");
// Authenticate and configure the virtual network interface.
handshake(tunnel);
System.out.println("handshake");
Thread.sleep(1000);
ToyVpnService.Builder builder = new ToyVpnService.Builder();
builder.setSession("ToyVPN").addAddress("xxx.xxx.xxx.xxx", 32)
.addRoute("1.0.0.0", 8)
.addRoute("2.0.0.0", 7)
.addRoute("4.0.0.0", 6)
.addRoute("8.0.0.0", 7)
.addRoute("11.0.0.0", 8)
.addRoute("12.0.0.0", 6)
.addRoute("16.0.0.0", 4)
.addRoute("32.0.0.0", 3)
.addRoute("64.0.0.0", 2)
.addRoute("139.0.0.0", 8)
.addRoute("140.0.0.0", 6)
.addRoute("144.0.0.0", 4)
.addRoute("160.0.0.0", 5)
.addRoute("168.0.0.0", 6)
.addRoute("172.0.0.0", 12)
.addRoute("172.32.0.0", 11)
.addRoute("172.64.0.0", 10)
.addRoute("172.128.0.0", 9)
.addRoute("173.0.0.0", 8)
.addRoute("174.0.0.0", 7)
.addRoute("176.0.0.0", 4)
.addRoute("192.0.0.0", 9)
.addRoute("192.128.0.0", 11)
.addRoute("192.160.0.0", 13)
.addRoute("192.169.0.0", 16)
.addRoute("192.170.0.0", 15)
.addRoute("192.172.0.0", 14)
.addRoute("192.176.0.0", 12)
.addRoute("192.192.0.0", 10)
.addRoute("193.0.0.0", 8)
.addRoute("194.0.0.0", 7)
.addRoute("196.0.0.0", 6)
.addRoute("200.0.0.0", 5)
.addRoute("208.0.0.0", 4)
.addRoute("224.0.0.0", 4)
.addRoute("240.0.0.0", 5)
.addRoute("248.0.0.0", 6)
.addRoute("252.0.0.0", 7)
.addRoute("254.0.0.0",8)
.addDnsServer("xxx.xxx.xxx.xxx")
.establish();
if (tunPFD == null) {
tunPFD = builder.establish();
if (tunPFD == null) {
System.out.println("stop");
stopSelf();
}
}
// Now we are connected. Set the flag and show the message.
connected = true;
mHandler.sendEmptyMessage(R.string.connected);
tunnel.configureBlocking(false);
// Packets to be sent are queued in this input stream.
FileInputStream in = new FileInputStream(tunPFD.getFileDescriptor());
// Packets received need to be written to this output stream.
FileOutputStream out = new FileOutputStream(tunPFD.getFileDescriptor());
int length = 0;
int count = 0;
while ((length == 0) && (count < 5000)) {
length = in.read(pptp.dataPack);
Thread.sleep(200);
count += 200;
System.out.println(count);
}
System.out.printf("read fd%d\n", tunPFD.getFd());
System.out.println(length);
System.out.println("write fd");
tunnel.write(pptp.packet);
Thread.sleep(2000);
} catch (InterruptedException e) {
throw e;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
tunnel.close();
} catch (Exception e) {
// ignore
}
}
return connected;
}
private void handshake(SocketChannel tunnel) throws Exception {
// To build a secured tunnel, we should perform mutual authentication
// and exchange session keys for encryption. To keep things simple in
// this demo, we just send the shared secret in plaintext and wait
// for the server to send the parameters.
// Allocate the buffer for handshaking.
// Control messages always start with zero.
tunnel.write(pptp.Start_Control_Req_Package());
// Wait for the parameters within a limited time.
Thread.sleep(100);
// Normally we should not receive random packets.
int length = tunnel.read(pptp.getEmptyPackage());
if (length <= 0 || pptp.getPacketType() != 2) {
System.out.println("start reply fail");
return;
}
tunnel.write(pptp.Outgoing_Call_Req_Package());
Thread.sleep(100);
length = tunnel.read(pptp.getEmptyPackage());
if (length <= 0 || pptp.getPacketType() != 8) {
System.out.println("outgoing reply fail");
return;
}
System.out.println("succeed");
}
pptp.Start_Control_Req_Package() guarantee to make a Start-Control-Request packet which can be reply by server. I have confirmed from tcpdump. Outgoing_Call is just the same. Then the server send back a PPP_LCP packet to request configuration, I don't know how to catch it and send back configurations.