[KA05] Export keepalive offload api for IpSec Nat-T file descriptor
Adds system api of createSocketKeepalive to take file descriptor, so privileged apps could use it without the need of IpSecService. Bug: 114151147 Test: atest FrameworksNetTests Change-Id: If926c21704b6ed73a0adfcadad732b97b42bacae
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package android.net;
|
||||
|
||||
import static android.net.IpSecManager.INVALID_RESOURCE_ID;
|
||||
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
@@ -61,6 +63,7 @@ import com.android.internal.util.Protocol;
|
||||
|
||||
import libcore.net.event.NetworkEventDispatcher;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.net.InetAddress;
|
||||
@@ -1849,8 +1852,39 @@ public class ConnectivityManager {
|
||||
@NonNull InetAddress destination,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull Callback callback) {
|
||||
return new NattSocketKeepalive(mService, network, socket, source, destination, executor,
|
||||
callback);
|
||||
return new NattSocketKeepalive(mService, network, socket.getFileDescriptor(),
|
||||
socket.getResourceId(), source, destination, executor, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request that keepalives be started on a IPsec NAT-T socket file descriptor. Directly called
|
||||
* by system apps which don't use IpSecService to create {@link UdpEncapsulationSocket}.
|
||||
*
|
||||
* @param network The {@link Network} the socket is on.
|
||||
* @param fd The {@link FileDescriptor} that needs to be kept alive. The provided
|
||||
* {@link FileDescriptor} must be bound to a port and the keepalives will be sent from
|
||||
* that port.
|
||||
* @param source The source address of the {@link UdpEncapsulationSocket}.
|
||||
* @param destination The destination address of the {@link UdpEncapsulationSocket}. The
|
||||
* keepalive packets will always be sent to port 4500 of the given {@code destination}.
|
||||
* @param executor The executor on which callback will be invoked. The provided {@link Executor}
|
||||
* must run callback sequentially, otherwise the order of callbacks cannot be
|
||||
* guaranteed.
|
||||
* @param callback A {@link SocketKeepalive.Callback}. Used for notifications about keepalive
|
||||
* changes. Must be extended by applications that use this API.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD)
|
||||
public SocketKeepalive createNattKeepalive(@NonNull Network network,
|
||||
@NonNull FileDescriptor fd,
|
||||
@NonNull InetAddress source,
|
||||
@NonNull InetAddress destination,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull Callback callback) {
|
||||
return new NattSocketKeepalive(mService, network, fd, INVALID_RESOURCE_ID /* Unused */,
|
||||
source, destination, executor, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -181,6 +181,10 @@ interface IConnectivityManager
|
||||
void startNattKeepalive(in Network network, int intervalSeconds, in Messenger messenger,
|
||||
in IBinder binder, String srcAddr, int srcPort, String dstAddr);
|
||||
|
||||
void startNattKeepaliveWithFd(in Network network, in FileDescriptor fd, int resourceId,
|
||||
int intervalSeconds, in Messenger messenger, in IBinder binder, String srcAddr,
|
||||
String dstAddr);
|
||||
|
||||
void stopKeepalive(in Network network, int slot);
|
||||
|
||||
String getCaptivePortalServerUrl();
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
package android.net;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.net.IpSecManager.UdpEncapsulationSocket;
|
||||
import android.os.Binder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.net.InetAddress;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@@ -32,11 +32,13 @@ public final class NattSocketKeepalive extends SocketKeepalive {
|
||||
|
||||
@NonNull private final InetAddress mSource;
|
||||
@NonNull private final InetAddress mDestination;
|
||||
@NonNull private final UdpEncapsulationSocket mSocket;
|
||||
@NonNull private final FileDescriptor mFd;
|
||||
private final int mResourceId;
|
||||
|
||||
NattSocketKeepalive(@NonNull IConnectivityManager service,
|
||||
@NonNull Network network,
|
||||
@NonNull UdpEncapsulationSocket socket,
|
||||
@NonNull FileDescriptor fd,
|
||||
int resourceId,
|
||||
@NonNull InetAddress source,
|
||||
@NonNull InetAddress destination,
|
||||
@NonNull Executor executor,
|
||||
@@ -44,15 +46,15 @@ public final class NattSocketKeepalive extends SocketKeepalive {
|
||||
super(service, network, executor, callback);
|
||||
mSource = source;
|
||||
mDestination = destination;
|
||||
mSocket = socket;
|
||||
mFd = fd;
|
||||
mResourceId = resourceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
void startImpl(int intervalSec) {
|
||||
try {
|
||||
// TODO: Create new interface in ConnectivityService and pass fd to it.
|
||||
mService.startNattKeepalive(mNetwork, intervalSec, mMessenger, new Binder(),
|
||||
mSource.getHostAddress(), mSocket.getPort(), mDestination.getHostAddress());
|
||||
mService.startNattKeepaliveWithFd(mNetwork, mFd, mResourceId, intervalSec, mMessenger,
|
||||
new Binder(), mSource.getHostAddress(), mDestination.getHostAddress());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error starting packet keepalive: ", e);
|
||||
stopLooper();
|
||||
|
||||
@@ -73,6 +73,7 @@ import android.net.INetworkStatsService;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.LinkProperties.CompareResult;
|
||||
import android.net.MatchAllNetworkSpecifier;
|
||||
import android.net.NattSocketKeepalive;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkAgent;
|
||||
import android.net.NetworkCapabilities;
|
||||
@@ -6184,6 +6185,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
srcAddr, srcPort, dstAddr, ConnectivityManager.PacketKeepalive.NATT_PORT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startNattKeepaliveWithFd(Network network, FileDescriptor fd, int resourceId,
|
||||
int intervalSeconds, Messenger messenger, IBinder binder, String srcAddr,
|
||||
String dstAddr) {
|
||||
enforceKeepalivePermission();
|
||||
mKeepaliveTracker.startNattKeepalive(
|
||||
getNetworkAgentInfoForNetwork(network), fd, resourceId,
|
||||
intervalSeconds, messenger, binder,
|
||||
srcAddr, dstAddr, NattSocketKeepalive.NATT_PORT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopKeepalive(Network network, int slot) {
|
||||
mHandler.sendMessage(mHandler.obtainMessage(
|
||||
|
||||
@@ -16,40 +16,49 @@
|
||||
|
||||
package com.android.server.connectivity;
|
||||
|
||||
import com.android.internal.util.HexDump;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.server.connectivity.NetworkAgentInfo;
|
||||
import android.net.ConnectivityManager;
|
||||
// TODO: Clean up imports and remove references of PacketKeepalive constants.
|
||||
|
||||
import static android.net.ConnectivityManager.PacketKeepalive.ERROR_INVALID_INTERVAL;
|
||||
import static android.net.ConnectivityManager.PacketKeepalive.ERROR_INVALID_IP_ADDRESS;
|
||||
import static android.net.ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK;
|
||||
import static android.net.ConnectivityManager.PacketKeepalive.MIN_INTERVAL;
|
||||
import static android.net.ConnectivityManager.PacketKeepalive.NATT_PORT;
|
||||
import static android.net.ConnectivityManager.PacketKeepalive.NO_KEEPALIVE;
|
||||
import static android.net.ConnectivityManager.PacketKeepalive.SUCCESS;
|
||||
import static android.net.NetworkAgent.CMD_START_PACKET_KEEPALIVE;
|
||||
import static android.net.NetworkAgent.CMD_STOP_PACKET_KEEPALIVE;
|
||||
import static android.net.NetworkAgent.EVENT_PACKET_KEEPALIVE;
|
||||
import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.net.ConnectivityManager.PacketKeepalive;
|
||||
import android.net.KeepalivePacketData;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.NetworkAgent;
|
||||
import android.net.NetworkUtils;
|
||||
import android.net.util.IpUtils;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.system.OsConstants;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import com.android.internal.util.HexDump;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static android.net.ConnectivityManager.PacketKeepalive.*;
|
||||
import static android.net.NetworkAgent.CMD_START_PACKET_KEEPALIVE;
|
||||
import static android.net.NetworkAgent.CMD_STOP_PACKET_KEEPALIVE;
|
||||
import static android.net.NetworkAgent.EVENT_PACKET_KEEPALIVE;
|
||||
|
||||
/**
|
||||
* Manages packet keepalive requests.
|
||||
*
|
||||
@@ -300,7 +309,9 @@ public class KeepaliveTracker {
|
||||
}
|
||||
}
|
||||
|
||||
public void handleEventPacketKeepalive(NetworkAgentInfo nai, Message message) {
|
||||
/** Handle keepalive events from lower layer. */
|
||||
public void handleEventPacketKeepalive(@NonNull NetworkAgentInfo nai,
|
||||
@NonNull Message message) {
|
||||
int slot = message.arg1;
|
||||
int reason = message.arg2;
|
||||
|
||||
@@ -330,8 +341,18 @@ public class KeepaliveTracker {
|
||||
}
|
||||
}
|
||||
|
||||
public void startNattKeepalive(NetworkAgentInfo nai, int intervalSeconds, Messenger messenger,
|
||||
IBinder binder, String srcAddrString, int srcPort, String dstAddrString, int dstPort) {
|
||||
/**
|
||||
* Called when requesting that keepalives be started on a IPsec NAT-T socket. See
|
||||
* {@link android.net.SocketKeepalive}.
|
||||
**/
|
||||
public void startNattKeepalive(@Nullable NetworkAgentInfo nai,
|
||||
int intervalSeconds,
|
||||
@NonNull Messenger messenger,
|
||||
@NonNull IBinder binder,
|
||||
@NonNull String srcAddrString,
|
||||
int srcPort,
|
||||
@NonNull String dstAddrString,
|
||||
int dstPort) {
|
||||
if (nai == null) {
|
||||
notifyMessenger(messenger, NO_KEEPALIVE, ERROR_INVALID_NETWORK);
|
||||
return;
|
||||
@@ -360,6 +381,56 @@ public class KeepaliveTracker {
|
||||
NetworkAgent.CMD_START_PACKET_KEEPALIVE, ki).sendToTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when requesting that keepalives be started on a IPsec NAT-T socket. This function is
|
||||
* identical to {@link #startNattKeepalive}, but also takes a {@code resourceId}, which is the
|
||||
* resource index bound to the {@link UdpEncapsulationSocket} when creating by
|
||||
* {@link com.android.server.IpSecService} to verify whether the given
|
||||
* {@link UdpEncapsulationSocket} is legitimate.
|
||||
**/
|
||||
public void startNattKeepalive(@Nullable NetworkAgentInfo nai,
|
||||
@Nullable FileDescriptor fd,
|
||||
int resourceId,
|
||||
int intervalSeconds,
|
||||
@NonNull Messenger messenger,
|
||||
@NonNull IBinder binder,
|
||||
@NonNull String srcAddrString,
|
||||
@NonNull String dstAddrString,
|
||||
int dstPort) {
|
||||
// Ensure that the socket is created by IpSecService.
|
||||
if (!isNattKeepaliveSocketValid(fd, resourceId)) {
|
||||
notifyMessenger(messenger, NO_KEEPALIVE, ERROR_INVALID_SOCKET);
|
||||
}
|
||||
|
||||
// Get src port to adopt old API.
|
||||
int srcPort = 0;
|
||||
try {
|
||||
final SocketAddress srcSockAddr = Os.getsockname(fd);
|
||||
srcPort = ((InetSocketAddress) srcSockAddr).getPort();
|
||||
} catch (ErrnoException e) {
|
||||
notifyMessenger(messenger, NO_KEEPALIVE, ERROR_INVALID_SOCKET);
|
||||
}
|
||||
|
||||
// Forward request to old API.
|
||||
startNattKeepalive(nai, intervalSeconds, messenger, binder, srcAddrString, srcPort,
|
||||
dstAddrString, dstPort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if the IPsec NAT-T file descriptor and resource Id hold for IPsec keepalive is valid.
|
||||
**/
|
||||
public static boolean isNattKeepaliveSocketValid(@Nullable FileDescriptor fd, int resourceId) {
|
||||
// TODO: 1. confirm whether the fd is called from system api or created by IpSecService.
|
||||
// 2. If the fd is created from the system api, check that it's bounded. And
|
||||
// call dup to keep the fd open.
|
||||
// 3. If the fd is created from IpSecService, check if the resource ID is valid. And
|
||||
// hold the resource needed in IpSecService.
|
||||
if (null == fd) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void dump(IndentingPrintWriter pw) {
|
||||
pw.println("Packet keepalives:");
|
||||
pw.increaseIndent();
|
||||
|
||||
@@ -3778,6 +3778,7 @@ public class ConnectivityServiceTest {
|
||||
// TODO: 1. Move this outside of ConnectivityServiceTest.
|
||||
// 2. Add helper function to test against newSingleThreadExecutor as well as inline
|
||||
// executor.
|
||||
// 3. Make test to verify that Nat-T keepalive socket is created by IpSecService.
|
||||
final int srcPort = 12345;
|
||||
final InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
|
||||
final InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
|
||||
|
||||
Reference in New Issue
Block a user