Reputation: 663
I am using VpnService API as shown in ToyVpn Android example;
The vpn device is opened correctly (the system icon is shown).
I get an exception when writing to the vpn interface. I try to write random bytes or a complete captured packet (in the example below) the result is the same, i.e. "Invalid argument".
The tun device descriptor is reported to be valid.
What could be the issue? Are there controls on the data being written to the vpn device?
Up to now I have tested this on two different emulators, with Android 7.1 and Android 4.2 and I get an exception in both cases.
Here is the complete log on Android 7.1:
02-01 11:01:08.099 ... I/MainActivity: onActivityResult
02-01 11:01:08.105 ... I/TestVpnService: opening tun device
02-01 11:01:08.118 ... I/TestVpnService: mInterface {ParcelFileDescriptor: java.io.FileDescriptor@c8cad37}
02-01 11:01:08.118 ... I/TestVpnService: mInterface FD: 45
02-01 11:01:08.118 ... I/TestVpnService: vpn descriptor valid? true
02-01 11:01:08.118 ... I/TestVpnService: testing write to tun device...
02-01 11:01:08.119 ... E/TestVpnService: error: Invalid argument
02-01 11:01:08.119 ... W/System.err: java.io.IOException: Invalid argument
02-01 11:01:08.119 ... W/System.err: at sun.nio.ch.FileDispatcherImpl.write0(Native Method)
02-01 11:01:08.119 ... W/System.err: at sun.nio.ch.FileDispatcherImpl.write(FileDispatcherImpl.java:63)
02-01 11:01:08.119 ... W/System.err: at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)
02-01 11:01:08.119 ... W/System.err: at sun.nio.ch.IOUtil.write(IOUtil.java:65)
02-01 11:01:08.119 ... W/System.err: at sun.nio.ch.FileChannelImpl.write(FileChannelImpl.java:214)
02-01 11:01:08.119 ... W/System.err: at testvpn.vpnwritetest.AndroidVpnService$override.onStartCommand(AndroidVpnService.java:71)
02-01 11:01:08.119 ... W/System.err: at testvpn.vpnwritetest.AndroidVpnService$override.access$dispatch(AndroidVpnService.java)
02-01 11:01:08.120 ... W/System.err: at testvpn.vpnwritetest.AndroidVpnService.onStartCommand(AndroidVpnService.java:0)
02-01 11:01:08.120 ... W/System.err: at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3326)
02-01 11:01:08.120 ... W/System.err: at android.app.ActivityThread.-wrap21(ActivityThread.java)
02-01 11:01:08.120 ... W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1582)
02-01 11:01:08.120 ... W/System.err: at android.os.Handler.dispatchMessage(Handler.java:102)
02-01 11:01:08.120 ... W/System.err: at android.os.Looper.loop(Looper.java:154)
02-01 11:01:08.120 ... W/System.err: at android.app.ActivityThread.main(ActivityThread.java:6119)
02-01 11:01:08.120 ... W/System.err: at java.lang.reflect.Method.invoke(Native Method)
02-01 11:01:08.120 ... W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
02-01 11:01:08.120 ... W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
02-01 11:01:08.120 ... I/TestVpnService: closing tun device
the manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="testvpn.vpnwritetest">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<service
android:name=".AndroidVpnService"
android:permission="android.permission.BIND_VPN_SERVICE">
<intent-filter>
<action android:name="android.net.VpnService" />
</intent-filter>
</service>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
the activity:
package testvpn.vpnwritetest;
import android.content.Intent;
import android.net.VpnService;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
Button button_vpn_test;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
button_vpn_test = (Button) findViewById(R.id.button_vpn_test);
button_vpn_test.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = VpnService.prepare(MainActivity.this);
if (intent != null) {
startActivityForResult(intent, 0);
} else {
onActivityResult(0, RESULT_OK, null);
}
}
});
}
@Override
protected void onActivityResult(int request, int result, Intent data) {
Log.i("MainActivity", "onActivityResult");
if (result == RESULT_OK) {
Intent intent = new Intent(this, AndroidVpnService.class);
startService(intent);
}
}
}
the service:
package testvpn.vpnwritetest;
import android.content.Intent;
import android.net.VpnService;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
/**
* Created by mrtexaz on 2/1/17.
*/
public class AndroidVpnService extends VpnService {
private static final String TAG = "TestVpnService";
private ParcelFileDescriptor mInterface;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "opening tun device");
Builder builder = new Builder();
builder = new Builder();
builder.setMtu(1500);
builder.addAddress("10.0.0.2", 24);
// builder.addRoute("0.0.0.0", 0);
mInterface = builder.establish();
Log.i(TAG,"mInterface " + mInterface);
Log.i(TAG,"mInterface FD: " + mInterface.getFd());
FileDescriptor df = mInterface.getFileDescriptor();
Log.i(TAG,"vpn descriptor valid? " + df.valid());
FileChannel vpnOutput = new FileOutputStream(mInterface.getFileDescriptor()).getChannel();
int [] testpayload = { 0x98, 0xe7, 0xf5, 0xd7, 0xce, 0xb6, 0x10, 0x02, 0xb5, 0x56, 0x59, 0x87, 0x08, 0x00, 0x45, 0x00,
0x00, 0x54, 0xd0, 0x93, 0x40, 0x00, 0x40, 0x01, 0xe6, 0x5f, 0xc0, 0xa8, 0x01, 0x64, 0xc0, 0xa8,
0x01, 0x01, 0x08, 0x00, 0x63, 0xc6, 0x7e, 0x2e, 0x00, 0x02, 0x95, 0xaa, 0x91, 0x58, 0x00, 0x00,
0x00, 0x00, 0x21, 0x33, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
0x36, 0x37};
ByteBuffer test = ByteBuffer.allocate(testpayload.length);
for (int i = 0; i < testpayload.length; i++) {
test.array()[i] = (byte) (testpayload[i] & 0xFF);
}
try {
Log.i(TAG, "testing write to tun device...");
vpnOutput.write(test);
Log.i(TAG, "testing write to tun device OK");
} catch (Exception ex) {
Log.e(TAG,"error: " + ex.getMessage());
ex.printStackTrace();
}
Log.i(TAG, "closing tun device");
try {
mInterface.close();
} catch (IOException e) {
e.printStackTrace();
}
return START_STICKY;
}
@Override
public void onDestroy() {
}
}
Upvotes: 1
Views: 1846
Reputation: 663
OK solved!
I need to write a valid tcp/ip packet to the tun device.
In the example, it is sufficient to remove the Ethernet II headers (the first 14 bytes of the sample array).
So using this sample payload, write to vpn device works:
int [] testpayload = {
//0x98, 0xe7, 0xf5, 0xd7, 0xce, 0xb6, 0x10, 0x02, 0xb5, 0x56, 0x59, 0x87, 0x08, 0x00,
0x45, 0x00,
0x00, 0x54, 0xd0, 0x93, 0x40, 0x00, 0x40, 0x01, 0xe6, 0x5f, 0xc0, 0xa8, 0x01, 0x64, 0xc0, 0xa8,
0x01, 0x01, 0x08, 0x00, 0x63, 0xc6, 0x7e, 0x2e, 0x00, 0x02, 0x95, 0xaa, 0x91, 0x58, 0x00, 0x00,
0x00, 0x00, 0x21, 0x33, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
0x36, 0x37};
Upvotes: 1