私は今数時間私の答えを探していました、そしてそれを理解することができません。助けてください。
私がしたいことは、AndroidでVpnServiceを使用して、アプリケーションのようなネットワークパケットを取得することです tPacketCapture
まず、GoogleのToyVpnサンプルコードを使用して、データをサーバーに送信しないようにコードを変更しました。ただし、これが正しいかどうかはわかりません。
私のconfigureメソッドは、estabrise()を呼び出す前に、binder.addAddress()にwlan ipアドレスを使用します。私はネクサス7を使用しており、「adb Shell netcfg | grep wlan0」を使用してアドレスを取得します。
wlan0 UP 192.168.0.6/24 0x00001043 10:bf:48:bf:5f:9d
そしてそれを私のメソッドに追加します:
private void configure() throws Exception {
// If the old interface has exactly the same parameters, use it!
if (mInterface != null) {
Log.i(TAG, "Using the previous interface");
return;
}
// Configure a builder while parsing the parameters.
Builder builder = new Builder();
builder.setMtu(1500);
builder.addAddress("192.168.0.6", 24);
try {
mInterface.close();
} catch (Exception e) {
// ignore
}
mInterface = builder.establish();
}
これを呼び出した後、InetSocketAddressの代わりに文字列を渡すように変更したrunメソッドを呼び出します。これはどこでも使用していないため、重要ではありません。
private void run(String run) throws Exception {
configure();
FileInputStream in = new FileInputStream(mInterface.getFileDescriptor());
// Allocate the buffer for a single packet.
ByteBuffer packet = ByteBuffer.allocate(32767);
// We use a timer to determine the status of the tunnel. It
// works on both sides. A positive value means sending, and
// any other means receiving. We start with receiving.
int timer = 0;
// 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) {
Log.i(TAG,"************new packet");
while (packet.hasRemaining()) {
Log.i(TAG,""+packet.get());
//System.out.print((char) packet.get());
}
// Write the outgoing packet to the tunnel.
packet.limit(length);
// tunnel.write(packet);
packet.clear();
// There might be more outgoing packets.
idle = false;
// If we were receiving, switch to sending.
if (timer < 1) {
timer = 1;
}
}
}
}
Adb logcatを実行しても、何も起こりません。私はこれについて正しく行っていますか?何かが足りないような気がします。
ありがとうございました!
編集:
ログから、次の行が表示されます。
I/ActivityManager( 460): START u0 {act=Android.intent.action.MAIN cat=[Android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.Android.toyvpn/.ToyVpnClient} from pid 10247
I/ActivityManager( 460): Start proc com.example.Android.toyvpn for activity com.example.Android.toyvpn/.ToyVpnClient: pid=10287 uid=10122 gids={50122, 3003, 1028}
I/ActivityManager( 460): Displayed com.example.Android.toyvpn/.ToyVpnClient: +1s144ms
I/Vpn ( 460): Switched from [Legacy VPN] to com.example.Android.toyvpn
D/Vpn ( 460): setting state=IDLE, reason=prepare
I/ToyVpnService(10287): running vpnService
D/Vpn ( 460): setting state=CONNECTING, reason=establish
D/VpnJni ( 460): Address added on tun0: 192.168.0.6/24
I/Vpn ( 460): Established by com.example.Android.toyvpn.ToyVpnService on tun0
W/ContextImpl( 460): Calling a method in the system process without a qualified user: Android.app.ContextImpl.bindService:1406 com.Android.server.connectivity.Vpn.establish:289 com.Android.server.ConnectivityService.establishVpn:3263 Android.net.IConnectivityManager$Stub.onTransact:504 Android.os.Binder.execTransact:351
D/Vpn ( 460): setting state=AUTHENTICATING, reason=establish
したがって、接続しているようです。
完全なソース:
public class ToyVpnService extends VpnService implements Handler.Callback, Runnable {
private static final String TAG = "ToyVpnService";
private Handler mHandler;
private Thread mThread;
private ParcelFileDescriptor mInterface;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// The handler is only used to show messages.
if (mHandler == null) {
mHandler = new Handler(this);
}
// Stop the previous session by interrupting the thread.
if (mThread != null) {
mThread.interrupt();
}
// Start a new session by creating a new thread.
mThread = new Thread(this, "ToyVpnThread");
mThread.start();
return START_STICKY;
}
@Override
public void onDestroy() {
if (mThread != null) {
mThread.interrupt();
}
}
@Override
public boolean handleMessage(Message message) {
if (message != null) {
Toast.makeText(this, message.what, Toast.LENGTH_SHORT).show();
}
return true;
}
@Override
public synchronized void run() {
Log.i(TAG,"running vpnService");
try {
runVpnConnection();
} catch (Exception e) {
e.printStackTrace();
//Log.e(TAG, "Got " + e.toString());
} finally {
try {
mInterface.close();
} catch (Exception e) {
// ignore
}
mInterface = null;
mHandler.sendEmptyMessage(R.string.disconnected);
Log.i(TAG, "Exiting");
}
}
private boolean runVpnConnection() throws Exception {
configure();
FileInputStream in = new FileInputStream(mInterface.getFileDescriptor());
// Allocate the buffer for a single packet.
ByteBuffer packet = ByteBuffer.allocate(32767);
// 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) {
Log.i(TAG,"************new packet");
System.exit(-1);
while (packet.hasRemaining()) {
Log.i(TAG,""+packet.get());
//System.out.print((char) packet.get());
}
packet.limit(length);
// tunnel.write(packet);
packet.clear();
// There might be more outgoing packets.
idle = false;
}
Thread.sleep(50);
}
}
public String getLocalIpAddress()
{
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
InetAddress inetAddress = enumIpAddr.nextElement();
Log.i(TAG,"****** INET ADDRESS ******");
Log.i(TAG,"address: "+inetAddress.getHostAddress());
Log.i(TAG,"hostname: "+inetAddress.getHostName());
Log.i(TAG,"address.toString(): "+inetAddress.getHostAddress().toString());
if (!inetAddress.isLoopbackAddress()) {
//IPAddresses.setText(inetAddress.getHostAddress().toString());
Log.i(TAG,"IS NOT LOOPBACK ADDRESS: "+inetAddress.getHostAddress().toString());
return inetAddress.getHostAddress().toString();
} else{
Log.i(TAG,"It is a loopback address");
}
}
}
} catch (SocketException ex) {
String LOG_TAG = null;
Log.e(LOG_TAG, ex.toString());
}
return null;
}
private void configure() throws Exception {
// If the old interface has exactly the same parameters, use it!
if (mInterface != null) {
Log.i(TAG, "Using the previous interface");
return;
}
// Configure a builder while parsing the parameters.
Builder builder = new Builder();
builder.setMtu(1500);
builder.addAddress("192.168.0.6", 24);
try {
mInterface.close();
} catch (Exception e) {
// ignore
}
mInterface = builder.establish();
}
}
わかりました。簡単ではありませんでしたが、パケットをキャプチャする方法を見つけました。私はネットワーキングにあまり詳しくないので(ただし、この新しい仕事は私に求められていることです)、すべてを正しく設定するのが困難でした。基本的に、VpnService.builderで正しいルートを設定した後、パケットを正しく受信しました。
そう:
builder.addAddress("192.168.0.6", 24); // was wrong, you need to put an internal IP (10.0.2.0 for example)
そして
builder.addRoute("0.0.0.0", 0); // needs to be this.
機能させるためにbuilder.addDnsServer()を使用してDnsServerをセットアップする必要はありません。これが誰にも役立つことを願っています!
私の構成メソッドは、> estabrise()を呼び出す前に、binder.addAddress()にwlan ipアドレスを使用します。私はネクサス7を使用しており、「adb Shell netcfg | grep> wlan0」を使用してアドレスを取得しました。
wlan0 UP 192.168.0.6/24 0x00001043 10:bf:48:bf:5f:9d
pythonにadbからnetcfgをグラフィカルに表示するための簡単なスクリプトを作成しました。毎秒更新されます。
https://github.com/ilanben/graphical_netcfg
楽しい :)