Merge changes Ie66ba631,Ic42c09a3
am: 6525e97ea5
Change-Id: I5c8a3364f0244c5945be2bbe919aac2dcc4eba66
This commit is contained in:
74
core/java/android/net/TestNetworkInterface.java
Normal file
74
core/java/android/net/TestNetworkInterface.java
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.net;
|
||||
|
||||
import android.annotation.TestApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* This class is used to return the interface name and fd of the test interface
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
public final class TestNetworkInterface implements Parcelable {
|
||||
private static final String TAG = "TestNetworkInterface";
|
||||
|
||||
private final ParcelFileDescriptor mFileDescriptor;
|
||||
private final String mInterfaceName;
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return (mFileDescriptor != null) ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeParcelable(mFileDescriptor, PARCELABLE_WRITE_RETURN_VALUE);
|
||||
out.writeString(mInterfaceName);
|
||||
}
|
||||
|
||||
public TestNetworkInterface(ParcelFileDescriptor pfd, String intf) {
|
||||
mFileDescriptor = pfd;
|
||||
mInterfaceName = intf;
|
||||
}
|
||||
|
||||
private TestNetworkInterface(Parcel in) {
|
||||
mFileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader());
|
||||
mInterfaceName = in.readString();
|
||||
}
|
||||
|
||||
public ParcelFileDescriptor getFileDescriptor() {
|
||||
return mFileDescriptor;
|
||||
}
|
||||
|
||||
public String getInterfaceName() {
|
||||
return mInterfaceName;
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<TestNetworkInterface> CREATOR =
|
||||
new Parcelable.Creator<TestNetworkInterface>() {
|
||||
public TestNetworkInterface createFromParcel(Parcel in) {
|
||||
return new TestNetworkInterface(in);
|
||||
}
|
||||
|
||||
public TestNetworkInterface[] newArray(int size) {
|
||||
return new TestNetworkInterface[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
91
core/java/android/net/TestNetworkManager.java
Normal file
91
core/java/android/net/TestNetworkManager.java
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.net;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.TestApi;
|
||||
import android.content.Context;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
/**
|
||||
* Class that allows creation and management of per-app, test-only networks
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
public class TestNetworkManager {
|
||||
@NonNull private static final String TAG = TestNetworkManager.class.getSimpleName();
|
||||
|
||||
@NonNull private final ITestNetworkManager mService;
|
||||
@NonNull private final Context mContext;
|
||||
|
||||
/** @hide */
|
||||
public TestNetworkManager(@NonNull Context context, @NonNull ITestNetworkManager service) {
|
||||
mContext = Preconditions.checkNotNull(context, "missing Context");
|
||||
mService = Preconditions.checkNotNull(service, "missing ITestNetworkManager");
|
||||
}
|
||||
|
||||
/**
|
||||
* Teardown the capability-limited, testing-only network for a given interface
|
||||
*
|
||||
* @param network The test network that should be torn down
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
public void teardownTestNetwork(@NonNull Network network) {
|
||||
try {
|
||||
mService.teardownTestNetwork(network.netId);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a capability-limited, testing-only network for a given interface
|
||||
*
|
||||
* @param iface the name of the interface to be used for the Network LinkProperties.
|
||||
* @param binder A binder object guarding the lifecycle of this test network.
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
public void setupTestNetwork(@NonNull String iface, @NonNull IBinder binder) {
|
||||
try {
|
||||
mService.setupTestNetwork(iface, binder);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a tun interface for testing purposes
|
||||
*
|
||||
* @param linkAddrs an array of LinkAddresses to assign to the TUN interface
|
||||
* @return A ParcelFileDescriptor of the underlying TUN interface. Close this to tear down the
|
||||
* TUN interface.
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) {
|
||||
try {
|
||||
return mService.createTunInterface(linkAddrs);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
338
services/core/java/com/android/server/TestNetworkService.java
Normal file
338
services/core/java/com/android/server/TestNetworkService.java
Normal file
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server;
|
||||
|
||||
import static com.android.internal.util.Preconditions.checkNotNull;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.INetd;
|
||||
import android.net.ITestNetworkManager;
|
||||
import android.net.IpPrefix;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.NetworkAgent;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.NetworkInfo.DetailedState;
|
||||
import android.net.RouteInfo;
|
||||
import android.net.StringNetworkSpecifier;
|
||||
import android.net.TestNetworkInterface;
|
||||
import android.net.util.NetdService;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
import android.os.INetworkManagementService;
|
||||
import android.os.Looper;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.RemoteException;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InterfaceAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/** @hide */
|
||||
class TestNetworkService extends ITestNetworkManager.Stub {
|
||||
@NonNull private static final String TAG = TestNetworkService.class.getSimpleName();
|
||||
@NonNull private static final String TEST_NETWORK_TYPE = "TEST_NETWORK";
|
||||
@NonNull private static final String TEST_TUN_PREFIX = "testtun";
|
||||
@NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger();
|
||||
|
||||
@NonNull private final Context mContext;
|
||||
@NonNull private final INetworkManagementService mNMS;
|
||||
@NonNull private final INetd mNetd;
|
||||
|
||||
@NonNull private final HandlerThread mHandlerThread;
|
||||
@NonNull private final Handler mHandler;
|
||||
|
||||
// Native method stubs
|
||||
private static native int jniCreateTun(@NonNull String iface);
|
||||
|
||||
@VisibleForTesting
|
||||
protected TestNetworkService(
|
||||
@NonNull Context context, @NonNull INetworkManagementService netManager) {
|
||||
mHandlerThread = new HandlerThread("TestNetworkServiceThread");
|
||||
mHandlerThread.start();
|
||||
mHandler = new Handler(mHandlerThread.getLooper());
|
||||
|
||||
mContext = checkNotNull(context, "missing Context");
|
||||
mNMS = checkNotNull(netManager, "missing INetworkManagementService");
|
||||
mNetd = checkNotNull(NetdService.getInstance(), "could not get netd instance");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a TUN interface with the given interface name and link addresses
|
||||
*
|
||||
* <p>This method will return the FileDescriptor to the TUN interface. Close it to tear down the
|
||||
* TUN interface.
|
||||
*/
|
||||
@Override
|
||||
public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) {
|
||||
enforceTestNetworkPermissions(mContext);
|
||||
|
||||
checkNotNull(linkAddrs, "missing linkAddrs");
|
||||
|
||||
String iface = TEST_TUN_PREFIX + sTestTunIndex.getAndIncrement();
|
||||
return Binder.withCleanCallingIdentity(
|
||||
() -> {
|
||||
try {
|
||||
ParcelFileDescriptor tunIntf =
|
||||
ParcelFileDescriptor.adoptFd(jniCreateTun(iface));
|
||||
for (LinkAddress addr : linkAddrs) {
|
||||
mNetd.interfaceAddAddress(
|
||||
iface,
|
||||
addr.getAddress().getHostAddress(),
|
||||
addr.getPrefixLength());
|
||||
}
|
||||
|
||||
return new TestNetworkInterface(tunIntf, iface);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Tracker for TestNetworkAgents
|
||||
@GuardedBy("mTestNetworkTracker")
|
||||
@NonNull
|
||||
private final SparseArray<TestNetworkAgent> mTestNetworkTracker = new SparseArray<>();
|
||||
|
||||
public class TestNetworkAgent extends NetworkAgent implements IBinder.DeathRecipient {
|
||||
private static final int NETWORK_SCORE = 1; // Use a low, non-zero score.
|
||||
|
||||
private final int mUid;
|
||||
@NonNull private final NetworkInfo mNi;
|
||||
@NonNull private final NetworkCapabilities mNc;
|
||||
@NonNull private final LinkProperties mLp;
|
||||
|
||||
@GuardedBy("mBinderLock")
|
||||
@NonNull
|
||||
private IBinder mBinder;
|
||||
|
||||
@NonNull private final Object mBinderLock = new Object();
|
||||
|
||||
private TestNetworkAgent(
|
||||
@NonNull Looper looper,
|
||||
@NonNull Context context,
|
||||
@NonNull NetworkInfo ni,
|
||||
@NonNull NetworkCapabilities nc,
|
||||
@NonNull LinkProperties lp,
|
||||
int uid,
|
||||
@NonNull IBinder binder)
|
||||
throws RemoteException {
|
||||
super(looper, context, TEST_NETWORK_TYPE, ni, nc, lp, NETWORK_SCORE);
|
||||
|
||||
mUid = uid;
|
||||
mNi = ni;
|
||||
mNc = nc;
|
||||
mLp = lp;
|
||||
|
||||
synchronized (mBinderLock) {
|
||||
mBinder = binder; // Binder null-checks in create()
|
||||
|
||||
try {
|
||||
mBinder.linkToDeath(this, 0);
|
||||
} catch (RemoteException e) {
|
||||
binderDied();
|
||||
throw e; // Abort, signal failure up the stack.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the Binder object dies, this function is called to free the resources of this
|
||||
* TestNetworkAgent
|
||||
*/
|
||||
@Override
|
||||
public void binderDied() {
|
||||
teardown();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unwanted() {
|
||||
teardown();
|
||||
}
|
||||
|
||||
private void teardown() {
|
||||
mNi.setDetailedState(DetailedState.DISCONNECTED, null, null);
|
||||
mNi.setIsAvailable(false);
|
||||
sendNetworkInfo(mNi);
|
||||
|
||||
// Synchronize on mBinderLock to ensure that unlinkToDeath is never called more than
|
||||
// once (otherwise it could throw an exception)
|
||||
synchronized (mBinderLock) {
|
||||
// If mBinder is null, this Test Network has already been cleaned up.
|
||||
if (mBinder == null) return;
|
||||
mBinder.unlinkToDeath(this, 0);
|
||||
mBinder = null;
|
||||
}
|
||||
|
||||
// Has to be in TestNetworkAgent to ensure all teardown codepaths properly clean up
|
||||
// resources, even for binder death or unwanted calls.
|
||||
synchronized (mTestNetworkTracker) {
|
||||
mTestNetworkTracker.remove(netId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TestNetworkAgent registerTestNetworkAgent(
|
||||
@NonNull Looper looper,
|
||||
@NonNull Context context,
|
||||
@NonNull String iface,
|
||||
int callingUid,
|
||||
@NonNull IBinder binder)
|
||||
throws RemoteException, SocketException {
|
||||
checkNotNull(looper, "missing Looper");
|
||||
checkNotNull(context, "missing Context");
|
||||
// iface and binder validity checked by caller
|
||||
|
||||
// Build network info with special testing type
|
||||
NetworkInfo ni = new NetworkInfo(ConnectivityManager.TYPE_TEST, 0, TEST_NETWORK_TYPE, "");
|
||||
ni.setDetailedState(DetailedState.CONNECTED, null, null);
|
||||
ni.setIsAvailable(true);
|
||||
|
||||
// Build narrow set of NetworkCapabilities, useful only for testing
|
||||
NetworkCapabilities nc = new NetworkCapabilities();
|
||||
nc.clearAll(); // Remove default capabilities.
|
||||
nc.addTransportType(NetworkCapabilities.TRANSPORT_TEST);
|
||||
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
|
||||
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
|
||||
nc.setNetworkSpecifier(new StringNetworkSpecifier(iface));
|
||||
|
||||
// Build LinkProperties
|
||||
LinkProperties lp = new LinkProperties();
|
||||
lp.setInterfaceName(iface);
|
||||
|
||||
// Find the currently assigned addresses, and add them to LinkProperties
|
||||
boolean allowIPv4 = false, allowIPv6 = false;
|
||||
NetworkInterface netIntf = NetworkInterface.getByName(iface);
|
||||
checkNotNull(netIntf, "No such network interface found: " + netIntf);
|
||||
|
||||
for (InterfaceAddress intfAddr : netIntf.getInterfaceAddresses()) {
|
||||
lp.addLinkAddress(
|
||||
new LinkAddress(intfAddr.getAddress(), intfAddr.getNetworkPrefixLength()));
|
||||
|
||||
if (intfAddr.getAddress() instanceof Inet6Address) {
|
||||
allowIPv6 |= !intfAddr.getAddress().isLinkLocalAddress();
|
||||
} else if (intfAddr.getAddress() instanceof Inet4Address) {
|
||||
allowIPv4 = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Add global routes (but as non-default, non-internet providing network)
|
||||
if (allowIPv4) {
|
||||
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null, iface));
|
||||
}
|
||||
if (allowIPv6) {
|
||||
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null, iface));
|
||||
}
|
||||
|
||||
return new TestNetworkAgent(looper, context, ni, nc, lp, callingUid, binder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a Network with extremely limited privileges, guarded by the MANAGE_TEST_NETWORKS
|
||||
* permission.
|
||||
*
|
||||
* <p>This method provides a Network that is useful only for testing.
|
||||
*/
|
||||
@Override
|
||||
public void setupTestNetwork(@NonNull String iface, @NonNull IBinder binder) {
|
||||
enforceTestNetworkPermissions(mContext);
|
||||
|
||||
checkNotNull(iface, "missing Iface");
|
||||
checkNotNull(binder, "missing IBinder");
|
||||
|
||||
if (!(iface.startsWith(INetd.IPSEC_INTERFACE_PREFIX)
|
||||
|| iface.startsWith(TEST_TUN_PREFIX))) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot create network for non ipsec, non-testtun interface");
|
||||
}
|
||||
|
||||
// Setup needs to be done with NETWORK_STACK privileges.
|
||||
int callingUid = Binder.getCallingUid();
|
||||
Binder.withCleanCallingIdentity(
|
||||
() -> {
|
||||
try {
|
||||
mNMS.setInterfaceUp(iface);
|
||||
|
||||
// Synchronize all accesses to mTestNetworkTracker to prevent the case
|
||||
// where:
|
||||
// 1. TestNetworkAgent successfully binds to death of binder
|
||||
// 2. Before it is added to the mTestNetworkTracker, binder dies,
|
||||
// binderDied() is called (on a different thread)
|
||||
// 3. This thread is pre-empted, put() is called after remove()
|
||||
synchronized (mTestNetworkTracker) {
|
||||
TestNetworkAgent agent =
|
||||
registerTestNetworkAgent(
|
||||
mHandler.getLooper(),
|
||||
mContext,
|
||||
iface,
|
||||
callingUid,
|
||||
binder);
|
||||
|
||||
mTestNetworkTracker.put(agent.netId, agent);
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Teardown a test network */
|
||||
@Override
|
||||
public void teardownTestNetwork(int netId) {
|
||||
enforceTestNetworkPermissions(mContext);
|
||||
|
||||
TestNetworkAgent agent;
|
||||
synchronized (mTestNetworkTracker) {
|
||||
agent = mTestNetworkTracker.get(netId);
|
||||
}
|
||||
|
||||
if (agent == null) {
|
||||
return; // Already torn down
|
||||
} else if (agent.mUid != Binder.getCallingUid()) {
|
||||
throw new SecurityException("Attempted to modify other user's test networks");
|
||||
}
|
||||
|
||||
// Safe to be called multiple times.
|
||||
agent.teardown();
|
||||
}
|
||||
|
||||
// STOPSHIP: Change this back to android.Manifest.permission.MANAGE_TEST_NETWORKS
|
||||
private static final String PERMISSION_NAME = "dummy";
|
||||
|
||||
public static void enforceTestNetworkPermissions(@NonNull Context context) {
|
||||
// STOPSHIP: Re-enable these checks. Disabled until adoptShellPermissionIdentity() can be
|
||||
// called from CTS test code.
|
||||
if (false) {
|
||||
context.enforceCallingOrSelfPermission(PERMISSION_NAME, "TestNetworkService");
|
||||
}
|
||||
}
|
||||
}
|
||||
107
services/core/jni/com_android_server_TestNetworkService.cpp
Normal file
107
services/core/jni/com_android_server_TestNetworkService.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_NDEBUG 0
|
||||
|
||||
#define LOG_TAG "TestNetworkServiceJni"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <linux/ipv6_route.h>
|
||||
#include <linux/route.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <log/log.h>
|
||||
|
||||
#include "netutils/ifc.h"
|
||||
|
||||
#include "jni.h"
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <nativehelper/JNIHelp.h>
|
||||
#include <nativehelper/ScopedUtfChars.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static void throwException(JNIEnv* env, int error, const char* action, const char* iface) {
|
||||
const std::string& msg =
|
||||
android::base::StringPrintf("Error %s %s: %s", action, iface, strerror(error));
|
||||
|
||||
jniThrowException(env, "java/lang/IllegalStateException", msg.c_str());
|
||||
}
|
||||
|
||||
static int createTunInterface(JNIEnv* env, const char* iface) {
|
||||
base::unique_fd tun(open("/dev/tun", O_RDWR | O_NONBLOCK));
|
||||
ifreq ifr{};
|
||||
|
||||
// Allocate interface.
|
||||
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
|
||||
strlcpy(ifr.ifr_name, iface, IFNAMSIZ);
|
||||
if (ioctl(tun.get(), TUNSETIFF, &ifr)) {
|
||||
throwException(env, errno, "allocating", ifr.ifr_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Activate interface using an unconnected datagram socket.
|
||||
base::unique_fd inet6CtrlSock(socket(AF_INET6, SOCK_DGRAM, 0));
|
||||
ifr.ifr_flags = IFF_UP;
|
||||
|
||||
if (ioctl(inet6CtrlSock.get(), SIOCSIFFLAGS, &ifr)) {
|
||||
throwException(env, errno, "activating", ifr.ifr_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return tun.release();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static jint create(JNIEnv* env, jobject /* thiz */, jstring jIface) {
|
||||
ScopedUtfChars iface(env, jIface);
|
||||
if (!iface.c_str()) {
|
||||
jniThrowNullPointerException(env, "iface");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int tun = createTunInterface(env, iface.c_str());
|
||||
|
||||
// Any exceptions will be thrown from the createTunInterface call
|
||||
return tun;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static const JNINativeMethod gMethods[] = {
|
||||
{"jniCreateTun", "(Ljava/lang/String;)I", (void*)create},
|
||||
};
|
||||
|
||||
int register_android_server_TestNetworkService(JNIEnv* env) {
|
||||
return jniRegisterNativeMethods(env, "com/android/server/TestNetworkService", gMethods,
|
||||
NELEM(gMethods));
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
Reference in New Issue
Block a user