Merge "Use token to identify IKE Session"

This commit is contained in:
Yan Yan
2022-05-16 20:27:52 +00:00
committed by Gerrit Code Review
2 changed files with 109 additions and 70 deletions

View File

@@ -2586,13 +2586,13 @@ public class Vpn {
void onDefaultNetworkLinkPropertiesChanged(@NonNull LinkProperties lp);
void onChildOpened(
@NonNull Network network, @NonNull ChildSessionConfiguration childConfig);
void onDefaultNetworkLost(@NonNull Network network);
void onChildTransformCreated(
@NonNull Network network, @NonNull IpSecTransform transform, int direction);
void onChildOpened(int token, @NonNull ChildSessionConfiguration childConfig);
void onSessionLost(@NonNull Network network, @Nullable Exception exception);
void onChildTransformCreated(int token, @NonNull IpSecTransform transform, int direction);
void onSessionLost(int token, @Nullable Exception exception);
}
/**
@@ -2639,6 +2639,13 @@ public class Vpn {
/** Signal to ensure shutdown is honored even if a new Network is connected. */
private boolean mIsRunning = true;
/**
* The token used by the primary/current/active IKE session.
*
* <p>This token MUST be updated when the VPN switches to use a new IKE session.
*/
private int mCurrentToken = -1;
@Nullable private IpSecTunnelInterface mTunnelIface;
@Nullable private IkeSession mSession;
@Nullable private Network mActiveNetwork;
@@ -2692,22 +2699,25 @@ public class Vpn {
return Objects.equals(mActiveNetwork, network) && mIsRunning;
}
private boolean isActiveToken(int token) {
return (mCurrentToken == token) && mIsRunning;
}
/**
* Called when an IKE Child session has been opened, signalling completion of the startup.
*
* <p>This method is only ever called once per IkeSession, and MUST run on the mExecutor
* thread in order to ensure consistency of the Ikev2VpnRunner fields.
*/
public void onChildOpened(
@NonNull Network network, @NonNull ChildSessionConfiguration childConfig) {
if (!isActiveNetwork(network)) {
Log.d(TAG, "onOpened called for obsolete network " + network);
public void onChildOpened(int token, @NonNull ChildSessionConfiguration childConfig) {
if (!isActiveToken(token)) {
Log.d(TAG, "onChildOpened called for obsolete token " + token);
// Do nothing; this signals that either: (1) a new/better Network was found,
// and the Ikev2VpnRunner has switched to it in onDefaultNetworkChanged, or (2) this
// IKE session was already shut down (exited, or an error was encountered somewhere
// else). In both cases, all resources and sessions are torn down via
// resetIkeState().
// and the Ikev2VpnRunner has switched to it by restarting a new IKE session in
// onDefaultNetworkChanged, or (2) this IKE session was already shut down (exited,
// or an error was encountered somewhere else). In both cases, all resources and
// sessions are torn down via resetIkeState().
return;
}
@@ -2744,7 +2754,7 @@ public class Vpn {
mConfig.dnsServers.clear();
mConfig.dnsServers.addAll(dnsAddrStrings);
mConfig.underlyingNetworks = new Network[] {network};
mConfig.underlyingNetworks = new Network[] {mActiveNetwork};
mConfig.disallowedApplications = getAppExclusionList(mPackage);
@@ -2760,7 +2770,8 @@ public class Vpn {
return; // Link properties are already sent.
} else {
// Underlying networks also set in agentConnect()
networkAgent.setUnderlyingNetworks(Collections.singletonList(network));
networkAgent.setUnderlyingNetworks(
Collections.singletonList(mActiveNetwork));
}
lp = makeLinkProperties(); // Accesses VPN instance fields; must be locked
@@ -2768,8 +2779,8 @@ public class Vpn {
networkAgent.sendLinkProperties(lp);
} catch (Exception e) {
Log.d(TAG, "Error in ChildOpened for network " + network, e);
onSessionLost(network, e);
Log.d(TAG, "Error in ChildOpened for token " + token, e);
onSessionLost(token, e);
}
}
@@ -2781,15 +2792,15 @@ public class Vpn {
* consistency of the Ikev2VpnRunner fields.
*/
public void onChildTransformCreated(
@NonNull Network network, @NonNull IpSecTransform transform, int direction) {
if (!isActiveNetwork(network)) {
Log.d(TAG, "ChildTransformCreated for obsolete network " + network);
int token, @NonNull IpSecTransform transform, int direction) {
if (!isActiveToken(token)) {
Log.d(TAG, "ChildTransformCreated for obsolete token " + token);
// Do nothing; this signals that either: (1) a new/better Network was found,
// and the Ikev2VpnRunner has switched to it in onDefaultNetworkChanged, or (2) this
// IKE session was already shut down (exited, or an error was encountered somewhere
// else). In both cases, all resources and sessions are torn down via
// resetIkeState().
// and the Ikev2VpnRunner has switched to it by restarting a new IKE session in
// onDefaultNetworkChanged, or (2) this IKE session was already shut down (exited,
// or an error was encountered somewhere else). In both cases, all resources and
// sessions are torn down via resetIkeState().
return;
}
@@ -2798,8 +2809,8 @@ public class Vpn {
// them alive for us
mIpSecManager.applyTunnelModeTransform(mTunnelIface, direction, transform);
} catch (IOException e) {
Log.d(TAG, "Transform application failed for network " + network, e);
onSessionLost(network, e);
Log.d(TAG, "Transform application failed for token " + token, e);
onSessionLost(token, e);
}
}
@@ -2857,19 +2868,21 @@ public class Vpn {
network);
NetdUtils.setInterfaceUp(mNetd, mTunnelIface.getInterfaceName());
mSession = mIkev2SessionCreator.createIkeSession(
mContext,
ikeSessionParams,
childSessionParams,
mExecutor,
new VpnIkev2Utils.IkeSessionCallbackImpl(
TAG, IkeV2VpnRunner.this, network),
new VpnIkev2Utils.ChildSessionCallbackImpl(
TAG, IkeV2VpnRunner.this, network));
Log.d(TAG, "Ike Session started for network " + network);
final int token = ++mCurrentToken;
mSession =
mIkev2SessionCreator.createIkeSession(
mContext,
ikeSessionParams,
childSessionParams,
mExecutor,
new VpnIkev2Utils.IkeSessionCallbackImpl(
TAG, IkeV2VpnRunner.this, token),
new VpnIkev2Utils.ChildSessionCallbackImpl(
TAG, IkeV2VpnRunner.this, token));
Log.d(TAG, "IKE session started for token " + token);
} catch (Exception e) {
Log.i(TAG, "Setup failed for network " + network + ". Aborting", e);
onSessionLost(network, e);
Log.i(TAG, "Setup failed for token " + mCurrentToken + ". Aborting", e);
onSessionLost(mCurrentToken, e);
}
}
@@ -2883,6 +2896,29 @@ public class Vpn {
mUnderlyingLinkProperties = lp;
}
/**
* Handles loss of the default underlying network
*
* <p>The Ikev2VpnRunner will kill the IKE session and reset the VPN.
*
* <p>This method MUST always be called on the mExecutor thread in order to ensure
* consistency of the Ikev2VpnRunner fields.
*/
public void onDefaultNetworkLost(@NonNull Network network) {
if (!isActiveNetwork(network)) {
Log.d(TAG, "onDefaultNetworkLost called for obsolete network " + network);
// Do nothing; this signals that either: (1) a new/better Network was found,
// and the Ikev2VpnRunner has switched to it by restarting a new IKE session in
// onDefaultNetworkChanged, or (2) this IKE session was already shut down (exited,
// or an error was encountered somewhere else). In both cases, all resources and
// sessions are torn down via resetIkeState().
return;
}
handleSessionLost(null);
}
/** Marks the state as FAILED, and disconnects. */
private void markFailedAndDisconnect(Exception exception) {
synchronized (Vpn.this) {
@@ -2901,18 +2937,22 @@ public class Vpn {
* <p>This method MUST always be called on the mExecutor thread in order to ensure
* consistency of the Ikev2VpnRunner fields.
*/
public void onSessionLost(@NonNull Network network, @Nullable Exception exception) {
if (!isActiveNetwork(network)) {
Log.d(TAG, "onSessionLost() called for obsolete network " + network);
public void onSessionLost(int token, @Nullable Exception exception) {
if (!isActiveToken(token)) {
Log.d(TAG, "onSessionLost() called for obsolete token " + token);
// Do nothing; this signals that either: (1) a new/better Network was found,
// and the Ikev2VpnRunner has switched to it in onDefaultNetworkChanged, or (2) this
// IKE session was already shut down (exited, or an error was encountered somewhere
// else). In both cases, all resources and sessions are torn down via
// onSessionLost() and resetIkeState().
// and the Ikev2VpnRunner has switched to it by restarting a new IKE session in
// onDefaultNetworkChanged, or (2) this IKE session was already shut down (exited,
// or an error was encountered somewhere else). In both cases, all resources and
// sessions are torn down via resetIkeState().
return;
}
handleSessionLost(exception);
}
private void handleSessionLost(@Nullable Exception exception) {
synchronized (Vpn.this) {
if (exception instanceof IkeProtocolException) {
final IkeProtocolException ikeException = (IkeProtocolException) exception;
@@ -3030,7 +3070,7 @@ public class Vpn {
// Close all obsolete state, but keep VPN alive incase a usable network comes up.
// (Mirrors VpnService behavior)
Log.d(TAG, "Resetting state for network: " + network);
Log.d(TAG, "Resetting state for token: " + mCurrentToken);
synchronized (Vpn.this) {
// Since this method handles non-fatal errors only, set mInterface to null to

View File

@@ -298,35 +298,35 @@ public class VpnIkev2Utils {
static class IkeSessionCallbackImpl implements IkeSessionCallback {
private final String mTag;
private final Vpn.IkeV2VpnRunnerCallback mCallback;
private final Network mNetwork;
private final int mToken;
IkeSessionCallbackImpl(String tag, Vpn.IkeV2VpnRunnerCallback callback, Network network) {
IkeSessionCallbackImpl(String tag, Vpn.IkeV2VpnRunnerCallback callback, int token) {
mTag = tag;
mCallback = callback;
mNetwork = network;
mToken = token;
}
@Override
public void onOpened(@NonNull IkeSessionConfiguration ikeSessionConfig) {
Log.d(mTag, "IkeOpened for network " + mNetwork);
Log.d(mTag, "IkeOpened for token " + mToken);
// Nothing to do here.
}
@Override
public void onClosed() {
Log.d(mTag, "IkeClosed for network " + mNetwork);
mCallback.onSessionLost(mNetwork, null); // Server requested session closure. Retry?
Log.d(mTag, "IkeClosed for token " + mToken);
mCallback.onSessionLost(mToken, null); // Server requested session closure. Retry?
}
@Override
public void onClosedExceptionally(@NonNull IkeException exception) {
Log.d(mTag, "IkeClosedExceptionally for network " + mNetwork, exception);
mCallback.onSessionLost(mNetwork, exception);
Log.d(mTag, "IkeClosedExceptionally for token " + mToken, exception);
mCallback.onSessionLost(mToken, exception);
}
@Override
public void onError(@NonNull IkeProtocolException exception) {
Log.d(mTag, "IkeError for network " + mNetwork, exception);
Log.d(mTag, "IkeError for token " + mToken, exception);
// Non-fatal, log and continue.
}
}
@@ -334,36 +334,36 @@ public class VpnIkev2Utils {
static class ChildSessionCallbackImpl implements ChildSessionCallback {
private final String mTag;
private final Vpn.IkeV2VpnRunnerCallback mCallback;
private final Network mNetwork;
private final int mToken;
ChildSessionCallbackImpl(String tag, Vpn.IkeV2VpnRunnerCallback callback, Network network) {
ChildSessionCallbackImpl(String tag, Vpn.IkeV2VpnRunnerCallback callback, int token) {
mTag = tag;
mCallback = callback;
mNetwork = network;
mToken = token;
}
@Override
public void onOpened(@NonNull ChildSessionConfiguration childConfig) {
Log.d(mTag, "ChildOpened for network " + mNetwork);
mCallback.onChildOpened(mNetwork, childConfig);
Log.d(mTag, "ChildOpened for token " + mToken);
mCallback.onChildOpened(mToken, childConfig);
}
@Override
public void onClosed() {
Log.d(mTag, "ChildClosed for network " + mNetwork);
mCallback.onSessionLost(mNetwork, null);
Log.d(mTag, "ChildClosed for token " + mToken);
mCallback.onSessionLost(mToken, null);
}
@Override
public void onClosedExceptionally(@NonNull IkeException exception) {
Log.d(mTag, "ChildClosedExceptionally for network " + mNetwork, exception);
mCallback.onSessionLost(mNetwork, exception);
Log.d(mTag, "ChildClosedExceptionally for token " + mToken, exception);
mCallback.onSessionLost(mToken, exception);
}
@Override
public void onIpSecTransformCreated(@NonNull IpSecTransform transform, int direction) {
Log.d(mTag, "ChildTransformCreated; Direction: " + direction + "; network " + mNetwork);
mCallback.onChildTransformCreated(mNetwork, transform, direction);
Log.d(mTag, "ChildTransformCreated; Direction: " + direction + "; token " + mToken);
mCallback.onChildTransformCreated(mToken, transform, direction);
}
@Override
@@ -371,8 +371,7 @@ public class VpnIkev2Utils {
// Nothing to be done; no references to the IpSecTransform are held by the
// Ikev2VpnRunner (or this callback class), and this transform will be closed by the
// IKE library.
Log.d(mTag,
"ChildTransformDeleted; Direction: " + direction + "; for network " + mNetwork);
Log.d(mTag, "ChildTransformDeleted; Direction: " + direction + "; for token " + mToken);
}
}
@@ -412,8 +411,8 @@ public class VpnIkev2Utils {
@Override
public void onLost(@NonNull Network network) {
Log.d(mTag, "Tearing down; lost network: " + network);
mExecutor.execute(() -> mCallback.onSessionLost(network, null));
Log.d(mTag, "onLost called for network: " + network);
mExecutor.execute(() -> mCallback.onDefaultNetworkLost(network));
}
}