我正在尝试使用 Android4.x VPN 服务与内部以太网服务器建立 VPN 隧道。IP 地址是 Internet 上的全球 ip。现在问题如下:
1.我使用TCP转储抓包,建立VPN Service.build后,没有tcp数据包可以在之前连接到服务器的隧道中传输。
2.构建建立后,我得到一个文件描述符,它不能写入任何字节(EINVAL错误),也不能读取任何字节(长度= 0)。
3.我使用socket隧道与服务器通信并发送PPTP数据包,经过start-control-request,outgoing-call-request,服务器返回正确的信息,然后通过PPP LCP协议传输配置信息。但是,我不知道接下来要做什么,如何获取 PPP LCP 数据包?它不是来自套接字,并且文件描述符无法读取或写入任何内容。
请大家帮忙,谢谢!
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() 保证生成一个可以被服务器回复的 Start-Control-Request 数据包。我已经从 tcpdump 确认了。Outgoing_Call 也一样。然后服务器发回一个 PPP_LCP 数据包请求配置,我不知道如何捕获它并发回配置。