Merge "Translate v4 keepalive packet on clat started network to v6"
This commit is contained in:
@@ -291,6 +291,18 @@ public class AutomaticOnOffKeepaliveTracker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new AutomaticOnOffKeepalive from existing AutomaticOnOffKeepalive with a
|
||||||
|
* new KeepaliveInfo.
|
||||||
|
*/
|
||||||
|
public AutomaticOnOffKeepalive withKeepaliveInfo(KeepaliveTracker.KeepaliveInfo ki)
|
||||||
|
throws InvalidSocketException {
|
||||||
|
return new AutomaticOnOffKeepalive(
|
||||||
|
ki,
|
||||||
|
mAutomaticOnOffState != STATE_ALWAYS_ON /* autoOnOff */,
|
||||||
|
mUnderpinnedNetwork);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "AutomaticOnOffKeepalive [ "
|
return "AutomaticOnOffKeepalive [ "
|
||||||
@@ -470,13 +482,26 @@ public class AutomaticOnOffKeepaliveTracker {
|
|||||||
* The message is expected to contain a KeepaliveTracker.KeepaliveInfo.
|
* The message is expected to contain a KeepaliveTracker.KeepaliveInfo.
|
||||||
*/
|
*/
|
||||||
public void handleStartKeepalive(Message message) {
|
public void handleStartKeepalive(Message message) {
|
||||||
final AutomaticOnOffKeepalive autoKi = (AutomaticOnOffKeepalive) message.obj;
|
final AutomaticOnOffKeepalive target = (AutomaticOnOffKeepalive) message.obj;
|
||||||
final int error = mKeepaliveTracker.handleStartKeepalive(autoKi.mKi);
|
final Pair<Integer, KeepaliveTracker.KeepaliveInfo> res =
|
||||||
|
mKeepaliveTracker.handleStartKeepalive(target.mKi);
|
||||||
|
final int error = res.first;
|
||||||
if (error != SUCCESS) {
|
if (error != SUCCESS) {
|
||||||
mEventLog.log("Failed to start keepalive " + autoKi.mCallback + " on "
|
mEventLog.log("Failed to start keepalive " + target.mCallback + " on "
|
||||||
+ autoKi.getNetwork() + " with error " + error);
|
+ target.getNetwork() + " with error " + error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Generate a new auto ki with the started keepalive info.
|
||||||
|
final AutomaticOnOffKeepalive autoKi;
|
||||||
|
try {
|
||||||
|
autoKi = target.withKeepaliveInfo(res.second);
|
||||||
|
// Close the duplicated fd.
|
||||||
|
target.close();
|
||||||
|
} catch (InvalidSocketException e) {
|
||||||
|
Log.wtf(TAG, "Fail to create AutomaticOnOffKeepalive", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mEventLog.log("Start keepalive " + autoKi.mCallback + " on " + autoKi.getNetwork());
|
mEventLog.log("Start keepalive " + autoKi.mCallback + " on " + autoKi.getNetwork());
|
||||||
mKeepaliveStatsTracker.onStartKeepalive(
|
mKeepaliveStatsTracker.onStartKeepalive(
|
||||||
autoKi.getNetwork(),
|
autoKi.getNetwork(),
|
||||||
@@ -506,14 +531,19 @@ public class AutomaticOnOffKeepaliveTracker {
|
|||||||
* @return SUCCESS if the keepalive is successfully starting and the error reason otherwise.
|
* @return SUCCESS if the keepalive is successfully starting and the error reason otherwise.
|
||||||
*/
|
*/
|
||||||
private int handleResumeKeepalive(@NonNull final KeepaliveTracker.KeepaliveInfo ki) {
|
private int handleResumeKeepalive(@NonNull final KeepaliveTracker.KeepaliveInfo ki) {
|
||||||
final int error = mKeepaliveTracker.handleStartKeepalive(ki);
|
final Pair<Integer, KeepaliveTracker.KeepaliveInfo> res =
|
||||||
|
mKeepaliveTracker.handleStartKeepalive(ki);
|
||||||
|
final KeepaliveTracker.KeepaliveInfo startedKi = res.second;
|
||||||
|
final int error = res.first;
|
||||||
if (error != SUCCESS) {
|
if (error != SUCCESS) {
|
||||||
mEventLog.log("Failed to resume keepalive " + ki.mCallback + " on " + ki.mNai
|
mEventLog.log("Failed to resume keepalive " + startedKi.mCallback + " on "
|
||||||
+ " with error " + error);
|
+ startedKi.mNai + " with error " + error);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
mKeepaliveStatsTracker.onResumeKeepalive(ki.getNai().network(), ki.getSlot());
|
|
||||||
mEventLog.log("Resumed successfully keepalive " + ki.mCallback + " on " + ki.mNai);
|
mKeepaliveStatsTracker.onResumeKeepalive(startedKi.getNai().network(), startedKi.getSlot());
|
||||||
|
mEventLog.log("Resumed successfully keepalive " + startedKi.mCallback
|
||||||
|
+ " on " + startedKi.mNai);
|
||||||
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ import android.os.RemoteException;
|
|||||||
import android.system.ErrnoException;
|
import android.system.ErrnoException;
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
import com.android.connectivity.resources.R;
|
import com.android.connectivity.resources.R;
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
@@ -62,6 +63,8 @@ import com.android.net.module.util.HexDump;
|
|||||||
import com.android.net.module.util.IpUtils;
|
import com.android.net.module.util.IpUtils;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.Inet6Address;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
@@ -292,11 +295,15 @@ public class KeepaliveTracker {
|
|||||||
|
|
||||||
private int checkSourceAddress() {
|
private int checkSourceAddress() {
|
||||||
// Check that we have the source address.
|
// Check that we have the source address.
|
||||||
for (InetAddress address : mNai.linkProperties.getAddresses()) {
|
for (InetAddress address : mNai.linkProperties.getAllAddresses()) {
|
||||||
if (address.equals(mPacket.getSrcAddress())) {
|
if (address.equals(mPacket.getSrcAddress())) {
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Or the address is the clat source address.
|
||||||
|
if (mPacket.getSrcAddress().equals(mNai.getClatv6SrcAddress())) {
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
return ERROR_INVALID_IP_ADDRESS;
|
return ERROR_INVALID_IP_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,6 +486,15 @@ public class KeepaliveTracker {
|
|||||||
return new KeepaliveInfo(mCallback, mNai, mPacket, mPid, mUid, mInterval, mType,
|
return new KeepaliveInfo(mCallback, mNai, mPacket, mPid, mUid, mInterval, mType,
|
||||||
fd, mSlot, true /* resumed */);
|
fd, mSlot, true /* resumed */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new KeepaliveInfo from existing KeepaliveInfo with a new KeepalivePacketData.
|
||||||
|
*/
|
||||||
|
public KeepaliveInfo withPacketData(@NonNull KeepalivePacketData packet)
|
||||||
|
throws InvalidSocketException {
|
||||||
|
return new KeepaliveInfo(mCallback, mNai, packet, mPid, mUid, mInterval, mType,
|
||||||
|
mFd, mSlot, mResumed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void notifyErrorCallback(ISocketKeepaliveCallback cb, int error) {
|
void notifyErrorCallback(ISocketKeepaliveCallback cb, int error) {
|
||||||
@@ -512,15 +528,47 @@ public class KeepaliveTracker {
|
|||||||
* Handle start keepalives with the message.
|
* Handle start keepalives with the message.
|
||||||
*
|
*
|
||||||
* @param ki the keepalive to start.
|
* @param ki the keepalive to start.
|
||||||
* @return SUCCESS if the keepalive is successfully starting and the error reason otherwise.
|
* @return Pair of (SUCCESS if the keepalive is successfully starting and the error reason
|
||||||
|
* otherwise, the started KeepaliveInfo object)
|
||||||
*/
|
*/
|
||||||
public int handleStartKeepalive(KeepaliveInfo ki) {
|
public Pair<Integer, KeepaliveInfo> handleStartKeepalive(KeepaliveInfo ki) {
|
||||||
NetworkAgentInfo nai = ki.getNai();
|
final KeepaliveInfo newKi;
|
||||||
|
try {
|
||||||
|
newKi = handleUpdateKeepaliveForClat(ki);
|
||||||
|
} catch (InvalidSocketException | InvalidPacketException e) {
|
||||||
|
Log.e(TAG, "Fail to construct keepalive packet");
|
||||||
|
notifyErrorCallback(ki.mCallback, ERROR_INVALID_IP_ADDRESS);
|
||||||
|
// Fail to create new keepalive packet for clat. Return the original keepalive info.
|
||||||
|
return new Pair<>(ERROR_INVALID_IP_ADDRESS, ki);
|
||||||
|
}
|
||||||
|
|
||||||
|
final NetworkAgentInfo nai = newKi.getNai();
|
||||||
// If this was a paused keepalive, then reuse the same slot that was kept for it. Otherwise,
|
// If this was a paused keepalive, then reuse the same slot that was kept for it. Otherwise,
|
||||||
// use the first free slot for this network agent.
|
// use the first free slot for this network agent.
|
||||||
final int slot = NO_KEEPALIVE != ki.mSlot ? ki.mSlot : findFirstFreeSlot(nai);
|
final int slot = NO_KEEPALIVE != newKi.mSlot ? newKi.mSlot : findFirstFreeSlot(nai);
|
||||||
mKeepalives.get(nai).put(slot, ki);
|
mKeepalives.get(nai).put(slot, newKi);
|
||||||
return ki.start(slot);
|
|
||||||
|
return new Pair<>(newKi.start(slot), newKi);
|
||||||
|
}
|
||||||
|
|
||||||
|
private KeepaliveInfo handleUpdateKeepaliveForClat(KeepaliveInfo ki)
|
||||||
|
throws InvalidSocketException, InvalidPacketException {
|
||||||
|
// Only try to translate address if the packet source address is the clat's source address.
|
||||||
|
if (!ki.mPacket.getSrcAddress().equals(ki.getNai().getClatv4SrcAddress())) return ki;
|
||||||
|
|
||||||
|
final InetAddress dstAddr = ki.mPacket.getDstAddress();
|
||||||
|
// Do not perform translation for a v6 dst address.
|
||||||
|
if (!(dstAddr instanceof Inet4Address)) return ki;
|
||||||
|
|
||||||
|
final Inet6Address address = ki.getNai().translateV4toClatV6((Inet4Address) dstAddr);
|
||||||
|
|
||||||
|
if (address == null) return ki;
|
||||||
|
|
||||||
|
final int srcPort = ki.mPacket.getSrcPort();
|
||||||
|
final KeepaliveInfo newInfo = ki.withPacketData(NattKeepalivePacketData.nattKeepalivePacket(
|
||||||
|
ki.getNai().getClatv6SrcAddress(), srcPort, address, NATT_PORT));
|
||||||
|
Log.d(TAG, "Src is clat v4 address. Convert from " + ki + " to " + newInfo);
|
||||||
|
return newInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleStopAllKeepalives(NetworkAgentInfo nai, int reason) {
|
public void handleStopAllKeepalives(NetworkAgentInfo nai, int reason) {
|
||||||
|
|||||||
@@ -6857,17 +6857,19 @@ public class ConnectivityServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPacketKeepalives() throws Exception {
|
public void testPacketKeepalives() throws Exception {
|
||||||
InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
|
final LinkAddress v4Addr = new LinkAddress("192.0.2.129/24");
|
||||||
|
final InetAddress myIPv4 = v4Addr.getAddress();
|
||||||
InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
|
InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
|
||||||
InetAddress myIPv6 = InetAddress.getByName("2001:db8::1");
|
InetAddress myIPv6 = InetAddress.getByName("2001:db8::1");
|
||||||
InetAddress dstIPv4 = InetAddress.getByName("8.8.8.8");
|
InetAddress dstIPv4 = InetAddress.getByName("8.8.8.8");
|
||||||
InetAddress dstIPv6 = InetAddress.getByName("2001:4860:4860::8888");
|
InetAddress dstIPv6 = InetAddress.getByName("2001:4860:4860::8888");
|
||||||
|
doReturn(getClatInterfaceConfigParcel(v4Addr)).when(mMockNetd)
|
||||||
|
.interfaceGetCfg(CLAT_MOBILE_IFNAME);
|
||||||
final int validKaInterval = 15;
|
final int validKaInterval = 15;
|
||||||
final int invalidKaInterval = 9;
|
final int invalidKaInterval = 9;
|
||||||
|
|
||||||
LinkProperties lp = new LinkProperties();
|
LinkProperties lp = new LinkProperties();
|
||||||
lp.setInterfaceName("wlan12");
|
lp.setInterfaceName(MOBILE_IFNAME);
|
||||||
lp.addLinkAddress(new LinkAddress(myIPv6, 64));
|
lp.addLinkAddress(new LinkAddress(myIPv6, 64));
|
||||||
lp.addLinkAddress(new LinkAddress(myIPv4, 25));
|
lp.addLinkAddress(new LinkAddress(myIPv4, 25));
|
||||||
lp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234")));
|
lp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234")));
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import android.content.Context;
|
|||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.net.INetd;
|
import android.net.INetd;
|
||||||
import android.net.ISocketKeepaliveCallback;
|
import android.net.ISocketKeepaliveCallback;
|
||||||
|
import android.net.InetAddresses;
|
||||||
import android.net.KeepalivePacketData;
|
import android.net.KeepalivePacketData;
|
||||||
import android.net.LinkAddress;
|
import android.net.LinkAddress;
|
||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
@@ -116,7 +117,8 @@ public class AutomaticOnOffKeepaliveTrackerTest {
|
|||||||
private static final int MOCK_RESOURCE_ID = 5;
|
private static final int MOCK_RESOURCE_ID = 5;
|
||||||
private static final int TEST_KEEPALIVE_INTERVAL_SEC = 10;
|
private static final int TEST_KEEPALIVE_INTERVAL_SEC = 10;
|
||||||
private static final int TEST_KEEPALIVE_INVALID_INTERVAL_SEC = 9;
|
private static final int TEST_KEEPALIVE_INVALID_INTERVAL_SEC = 9;
|
||||||
|
private static final byte[] V4_SRC_ADDR = new byte[] { (byte) 192, 0, 0, (byte) 129 };
|
||||||
|
private static final String TEST_V4_IFACE = "v4-testIface";
|
||||||
private AutomaticOnOffKeepaliveTracker mAOOKeepaliveTracker;
|
private AutomaticOnOffKeepaliveTracker mAOOKeepaliveTracker;
|
||||||
private HandlerThread mHandlerThread;
|
private HandlerThread mHandlerThread;
|
||||||
|
|
||||||
@@ -327,6 +329,8 @@ public class AutomaticOnOffKeepaliveTrackerTest {
|
|||||||
NetworkInfo.DetailedState.CONNECTED, "test reason", "test extra info");
|
NetworkInfo.DetailedState.CONNECTED, "test reason", "test extra info");
|
||||||
doReturn(new Network(TEST_NETID)).when(mNai).network();
|
doReturn(new Network(TEST_NETID)).when(mNai).network();
|
||||||
mNai.linkProperties = new LinkProperties();
|
mNai.linkProperties = new LinkProperties();
|
||||||
|
doReturn(null).when(mNai).translateV4toClatV6(any());
|
||||||
|
doReturn(null).when(mNai).getClatv6SrcAddress();
|
||||||
|
|
||||||
doReturn(PERMISSION_GRANTED).when(mCtx).checkPermission(any() /* permission */,
|
doReturn(PERMISSION_GRANTED).when(mCtx).checkPermission(any() /* permission */,
|
||||||
anyInt() /* pid */, anyInt() /* uid */);
|
anyInt() /* pid */, anyInt() /* uid */);
|
||||||
@@ -429,8 +433,7 @@ public class AutomaticOnOffKeepaliveTrackerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TestKeepaliveInfo doStartNattKeepalive(int intervalSeconds) throws Exception {
|
private TestKeepaliveInfo doStartNattKeepalive(int intervalSeconds) throws Exception {
|
||||||
final InetAddress srcAddress = InetAddress.getByAddress(
|
final InetAddress srcAddress = InetAddress.getByAddress(V4_SRC_ADDR);
|
||||||
new byte[] { (byte) 192, 0, 0, (byte) 129 });
|
|
||||||
final int srcPort = 12345;
|
final int srcPort = 12345;
|
||||||
final InetAddress dstAddress = InetAddress.getByAddress(new byte[] {8, 8, 8, 8});
|
final InetAddress dstAddress = InetAddress.getByAddress(new byte[] {8, 8, 8, 8});
|
||||||
final int dstPort = 12345;
|
final int dstPort = 12345;
|
||||||
@@ -609,6 +612,42 @@ public class AutomaticOnOffKeepaliveTrackerTest {
|
|||||||
verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
|
verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStartNattKeepalive_addressTranslationOnClat() throws Exception {
|
||||||
|
final InetAddress v6AddrSrc = InetAddresses.parseNumericAddress("2001:db8::1");
|
||||||
|
final InetAddress v6AddrDst = InetAddresses.parseNumericAddress("2001:db8::2");
|
||||||
|
doReturn(v6AddrDst).when(mNai).translateV4toClatV6(any());
|
||||||
|
doReturn(v6AddrSrc).when(mNai).getClatv6SrcAddress();
|
||||||
|
doReturn(InetAddress.getByAddress(V4_SRC_ADDR)).when(mNai).getClatv4SrcAddress();
|
||||||
|
// Setup nai to add clat address
|
||||||
|
final LinkProperties stacked = new LinkProperties();
|
||||||
|
stacked.setInterfaceName(TEST_V4_IFACE);
|
||||||
|
mNai.linkProperties.addStackedLink(stacked);
|
||||||
|
|
||||||
|
final TestKeepaliveInfo testInfo = doStartNattKeepalive();
|
||||||
|
final ArgumentCaptor<NattKeepalivePacketData> kpdCaptor =
|
||||||
|
ArgumentCaptor.forClass(NattKeepalivePacketData.class);
|
||||||
|
verify(mNai).onStartNattSocketKeepalive(
|
||||||
|
eq(TEST_SLOT), eq(TEST_KEEPALIVE_INTERVAL_SEC), kpdCaptor.capture());
|
||||||
|
final NattKeepalivePacketData kpd = kpdCaptor.getValue();
|
||||||
|
// Verify the addresses are updated to v6 when clat is started.
|
||||||
|
assertEquals(v6AddrSrc, kpd.getSrcAddress());
|
||||||
|
assertEquals(v6AddrDst, kpd.getDstAddress());
|
||||||
|
|
||||||
|
triggerEventKeepalive(TEST_SLOT, SocketKeepalive.SUCCESS);
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onStarted();
|
||||||
|
|
||||||
|
// Remove clat address should stop the keepalive.
|
||||||
|
doReturn(null).when(mNai).getClatv6SrcAddress();
|
||||||
|
visibleOnHandlerThread(
|
||||||
|
mTestHandler, () -> mAOOKeepaliveTracker.handleCheckKeepalivesStillValid(mNai));
|
||||||
|
checkAndProcessKeepaliveStop();
|
||||||
|
assertNull(getAutoKiForBinder(testInfo.binder));
|
||||||
|
|
||||||
|
verify(testInfo.socketKeepaliveCallback).onError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
|
||||||
|
verifyNoMoreInteractions(ignoreStubs(testInfo.socketKeepaliveCallback));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHandleEventSocketKeepalive_startingFailureHardwareError() throws Exception {
|
public void testHandleEventSocketKeepalive_startingFailureHardwareError() throws Exception {
|
||||||
final TestKeepaliveInfo testInfo = doStartNattKeepalive();
|
final TestKeepaliveInfo testInfo = doStartNattKeepalive();
|
||||||
|
|||||||
Reference in New Issue
Block a user