Android4.x VPN サービスを使用して、内部イーサネット サーバーとの VPN トンネルを確立しようとしています。IP アドレスは、インターネット上のグローバル IP です。問題は次のとおりです。
1.TCP ダンプを使用してパケットをキャッチします。VPN Service.build が確立された後、以前にサーバーに接続されていたトンネルで tcp パケットを転送できません。
2.ビルドが確立された後、fileDescriptor を取得します。バイトを書き込むことができず (EINVAL エラー)、バイトを読み取ることができません (長さ = 0)。
3. ソケット トンネルを使用してサーバーと通信し、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 パケットを送り返します。それをキャッチして構成を送り返す方法がわかりません。