Loading core/java/android/net/IIpSecService.aidl +22 −0 Original line number Diff line number Diff line Loading @@ -16,9 +16,31 @@ package android.net; import android.net.Network; import android.net.IpSecConfig; import android.os.Bundle; import android.os.IBinder; import android.os.ParcelFileDescriptor; /** * @hide */ interface IIpSecService { Bundle reserveSecurityParameterIndex( int direction, in String remoteAddress, int requestedSpi, in IBinder binder); void releaseSecurityParameterIndex(int resourceId); Bundle openUdpEncapsulationSocket(int port, in IBinder binder); void closeUdpEncapsulationSocket(in ParcelFileDescriptor socket); Bundle createTransportModeTransform(in IpSecConfig c, in IBinder binder); void deleteTransportModeTransform(int transformId); void applyTransportModeTransform(in ParcelFileDescriptor socket, int transformId); void removeTransportModeTransform(in ParcelFileDescriptor socket, int transformId); } core/java/android/net/IpSecAlgorithm.java +2 −0 Original line number Diff line number Diff line Loading @@ -164,6 +164,8 @@ public final class IpSecAlgorithm implements Parcelable { private static boolean isTruncationLengthValid(String algo, int truncLenBits) { switch (algo) { case ALGO_CRYPT_AES_CBC: return (truncLenBits == 128 || truncLenBits == 192 || truncLenBits == 256); case ALGO_AUTH_HMAC_MD5: return (truncLenBits >= 96 && truncLenBits <= 128); case ALGO_AUTH_HMAC_SHA1: Loading core/java/android/net/IpSecConfig.java +26 −44 Original line number Diff line number Diff line Loading @@ -23,7 +23,7 @@ import java.net.UnknownHostException; /** @hide */ public final class IpSecConfig implements Parcelable { private static final String TAG = IpSecConfig.class.getSimpleName(); private static final String TAG = "IpSecConfig"; //MODE_TRANSPORT or MODE_TUNNEL int mode; Loading @@ -43,13 +43,13 @@ public final class IpSecConfig implements Parcelable { int spi; // Encryption Algorithm IpSecAlgorithm encryptionAlgo; IpSecAlgorithm encryption; // Authentication Algorithm IpSecAlgorithm authenticationAlgo; IpSecAlgorithm authentication; } Flow[] flow = new Flow[2]; Flow[] flow = new Flow[] {new Flow(), new Flow()}; // For tunnel mode IPv4 UDP Encapsulation // IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE Loading @@ -57,17 +57,15 @@ public final class IpSecConfig implements Parcelable { int encapLocalPort; int encapRemotePort; // An optional protocol to match with the selector int selectorProto; // A bitmask of FEATURE_* indicating which of the fields // of this class are valid. long features; // An interval, in seconds between the NattKeepalive packets int nattKeepaliveInterval; public InetAddress getLocalIp() { // Transport or Tunnel public int getMode() { return mode; } public InetAddress getLocalAddress() { return localAddress; } Loading @@ -75,19 +73,19 @@ public final class IpSecConfig implements Parcelable { return flow[direction].spi; } public InetAddress getRemoteIp() { public InetAddress getRemoteAddress() { return remoteAddress; } public IpSecAlgorithm getEncryptionAlgo(int direction) { return flow[direction].encryptionAlgo; public IpSecAlgorithm getEncryption(int direction) { return flow[direction].encryption; } public IpSecAlgorithm getAuthenticationAlgo(int direction) { return flow[direction].authenticationAlgo; public IpSecAlgorithm getAuthentication(int direction) { return flow[direction].authentication; } Network getNetwork() { public Network getNetwork() { return network; } Loading @@ -103,18 +101,10 @@ public final class IpSecConfig implements Parcelable { return encapRemotePort; } public int getSelectorProto() { return selectorProto; } int getNattKeepaliveInterval() { public int getNattKeepaliveInterval() { return nattKeepaliveInterval; } public boolean hasProperty(int featureBits) { return (features & featureBits) == featureBits; } // Parcelable Methods @Override Loading @@ -124,31 +114,25 @@ public final class IpSecConfig implements Parcelable { @Override public void writeToParcel(Parcel out, int flags) { out.writeLong(features); // TODO: Use a byte array or other better method for storing IPs that can also include scope out.writeString((localAddress != null) ? localAddress.getHostAddress() : null); // TODO: Use a byte array or other better method for storing IPs that can also include scope out.writeString((remoteAddress != null) ? remoteAddress.getHostAddress() : null); out.writeParcelable(network, flags); out.writeInt(flow[IpSecTransform.DIRECTION_IN].spi); out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryptionAlgo, flags); out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authenticationAlgo, flags); out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryption, flags); out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authentication, flags); out.writeInt(flow[IpSecTransform.DIRECTION_OUT].spi); out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo, flags); out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo, flags); out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryption, flags); out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authentication, flags); out.writeInt(encapType); out.writeInt(encapLocalPort); out.writeInt(encapRemotePort); out.writeInt(selectorProto); } // Package Private: Used by the IpSecTransform.Builder; // there should be no public constructor for this object IpSecConfig() { flow[IpSecTransform.DIRECTION_IN].spi = 0; flow[IpSecTransform.DIRECTION_OUT].spi = 0; nattKeepaliveInterval = 0; //FIXME constant } IpSecConfig() {} private static InetAddress readInetAddressFromParcel(Parcel in) { String addrString = in.readString(); Loading @@ -164,24 +148,22 @@ public final class IpSecConfig implements Parcelable { } private IpSecConfig(Parcel in) { features = in.readLong(); localAddress = readInetAddressFromParcel(in); remoteAddress = readInetAddressFromParcel(in); network = (Network) in.readParcelable(Network.class.getClassLoader()); flow[IpSecTransform.DIRECTION_IN].spi = in.readInt(); flow[IpSecTransform.DIRECTION_IN].encryptionAlgo = flow[IpSecTransform.DIRECTION_IN].encryption = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); flow[IpSecTransform.DIRECTION_IN].authenticationAlgo = flow[IpSecTransform.DIRECTION_IN].authentication = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); flow[IpSecTransform.DIRECTION_OUT].spi = in.readInt(); flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo = flow[IpSecTransform.DIRECTION_OUT].encryption = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo = flow[IpSecTransform.DIRECTION_OUT].authentication = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); encapType = in.readInt(); encapLocalPort = in.readInt(); encapRemotePort = in.readInt(); selectorProto = in.readInt(); } public static final Parcelable.Creator<IpSecConfig> CREATOR = Loading core/java/android/net/IpSecManager.java +90 −22 Original line number Diff line number Diff line Loading @@ -17,8 +17,11 @@ package android.net; import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.SystemApi; import android.annotation.NonNull; import android.os.Binder; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.AndroidException; import dalvik.system.CloseGuard; import java.io.FileDescriptor; Loading @@ -38,6 +41,29 @@ import java.net.Socket; public final class IpSecManager { private static final String TAG = "IpSecManager"; /** * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index. * * <p>No IPsec packet may contain an SPI of 0. */ public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; /** @hide */ public interface Status { public static final int OK = 0; public static final int RESOURCE_UNAVAILABLE = 1; public static final int SPI_UNAVAILABLE = 2; } /** @hide */ public static final String KEY_STATUS = "status"; /** @hide */ public static final String KEY_RESOURCE_ID = "resourceId"; /** @hide */ public static final String KEY_SPI = "spi"; /** @hide */ public static final int INVALID_RESOURCE_ID = 0; /** * Indicates that the combination of remote InetAddress and SPI was non-unique for a given * request. If encountered, selection of a new SPI is required before a transform may be Loading Loading @@ -83,22 +109,14 @@ public final class IpSecManager { private final IIpSecService mService; private final InetAddress mRemoteAddress; private final CloseGuard mCloseGuard = CloseGuard.get(); private int mSpi; private int mSpi = INVALID_SECURITY_PARAMETER_INDEX; private int mResourceId; /** Return the underlying SPI held by this object */ public int getSpi() { return mSpi; } private SecurityParameterIndex( IIpSecService service, int direction, InetAddress remoteAddress, int spi) throws ResourceUnavailableException, SpiUnavailableException { mService = service; mRemoteAddress = remoteAddress; mSpi = spi; mCloseGuard.open("open"); } /** * Release an SPI that was previously reserved. * Loading @@ -108,7 +126,7 @@ public final class IpSecManager { */ @Override public void close() { mSpi = INVALID_SECURITY_PARAMETER_INDEX; // TODO: Invalid SPI mSpi = INVALID_SECURITY_PARAMETER_INDEX; mCloseGuard.close(); } Loading @@ -120,14 +138,52 @@ public final class IpSecManager { close(); } private SecurityParameterIndex( @NonNull IIpSecService service, int direction, InetAddress remoteAddress, int spi) throws ResourceUnavailableException, SpiUnavailableException { mService = service; mRemoteAddress = remoteAddress; try { Bundle result = mService.reserveSecurityParameterIndex( direction, remoteAddress.getHostAddress(), spi, new Binder()); if (result == null) { throw new NullPointerException("Received null response from IpSecService"); } int status = result.getInt(KEY_STATUS); switch (status) { case Status.OK: break; case Status.RESOURCE_UNAVAILABLE: throw new ResourceUnavailableException( "No more SPIs may be allocated by this requester."); case Status.SPI_UNAVAILABLE: throw new SpiUnavailableException("Requested SPI is unavailable", spi); default: throw new RuntimeException( "Unknown status returned by IpSecService: " + status); } mSpi = result.getInt(KEY_SPI); mResourceId = result.getInt(KEY_RESOURCE_ID); /** * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index. * * <p>No IPsec packet may contain an SPI of 0. */ public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; if (mSpi == INVALID_SECURITY_PARAMETER_INDEX) { throw new RuntimeException("Invalid SPI returned by IpSecService: " + status); } if (mResourceId == INVALID_RESOURCE_ID) { throw new RuntimeException( "Invalid Resource ID returned by IpSecService: " + status); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } mCloseGuard.open("open"); } } /** * Reserve an SPI for traffic bound towards the specified remote address. Loading Loading @@ -184,7 +240,13 @@ public final class IpSecManager { } /* Call down to activate a transform */ private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {} private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { try { mService.applyTransportModeTransform(pfd, transform.getResourceId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Apply an active Tunnel Mode IPsec Transform to a network, which will tunnel all traffic to Loading Loading @@ -228,7 +290,13 @@ public final class IpSecManager { } /* Call down to activate a transform */ private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {} private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { try { mService.removeTransportModeTransform(pfd, transform.getResourceId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of Loading @@ -255,7 +323,7 @@ public final class IpSecManager { private final IIpSecService mService; private final CloseGuard mCloseGuard = CloseGuard.get(); private UdpEncapsulationSocket(IIpSecService service, int port) private UdpEncapsulationSocket(@NonNull IIpSecService service, int port) throws ResourceUnavailableException { mService = service; mCloseGuard.open("constructor"); Loading core/java/android/net/IpSecTransform.java +92 −51 Original line number Diff line number Diff line Loading @@ -15,11 +15,21 @@ */ package android.net; import static android.net.IpSecManager.INVALID_RESOURCE_ID; import static android.net.IpSecManager.KEY_RESOURCE_ID; import static android.net.IpSecManager.KEY_STATUS; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.content.Context; import android.system.ErrnoException; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import com.android.internal.util.Preconditions; import dalvik.system.CloseGuard; import java.io.IOException; import java.lang.annotation.Retention; Loading Loading @@ -86,39 +96,64 @@ public final class IpSecTransform implements AutoCloseable { @Retention(RetentionPolicy.SOURCE) public @interface EncapType {} /** * Sentinel for an invalid transform (means that this transform is inactive). * * @hide */ public static final int INVALID_TRANSFORM_ID = -1; private IpSecTransform(Context context, IpSecConfig config) { mContext = context; mConfig = config; mTransformId = INVALID_TRANSFORM_ID; mResourceId = INVALID_RESOURCE_ID; } private IIpSecService getIpSecService() { IBinder b = ServiceManager.getService(android.content.Context.IPSEC_SERVICE); if (b == null) { throw new RemoteException("Failed to connect to IpSecService") .rethrowAsRuntimeException(); } return IIpSecService.Stub.asInterface(b); } private void checkResultStatusAndThrow(int status) throws IOException, IpSecManager.ResourceUnavailableException, IpSecManager.SpiUnavailableException { switch (status) { case IpSecManager.Status.OK: return; // TODO: Pass Error string back from bundle so that errors can be more specific case IpSecManager.Status.RESOURCE_UNAVAILABLE: throw new IpSecManager.ResourceUnavailableException( "Failed to allocate a new IpSecTransform"); case IpSecManager.Status.SPI_UNAVAILABLE: Log.wtf(TAG, "Attempting to use an SPI that was somehow not reserved"); // Fall through default: throw new IllegalStateException( "Failed to Create a Transform with status code " + status); } } private IpSecTransform activate() throws IOException, IpSecManager.ResourceUnavailableException, IpSecManager.SpiUnavailableException { int transformId; synchronized (this) { //try { transformId = INVALID_TRANSFORM_ID; //} catch (RemoteException e) { // throw e.rethrowFromSystemServer(); //} if (transformId < 0) { throw new ErrnoException("addTransform", -transformId).rethrowAsIOException(); try { IIpSecService svc = getIpSecService(); Bundle result = svc.createTransportModeTransform(mConfig, new Binder()); int status = result.getInt(KEY_STATUS); checkResultStatusAndThrow(status); mResourceId = result.getInt(KEY_RESOURCE_ID, INVALID_RESOURCE_ID); /* Keepalive will silently fail if not needed by the config; but, if needed and * it fails to start, we need to bail because a transform will not be reliable * to use if keepalive is expected to offload and fails. */ // FIXME: if keepalive fails, we need to fail spectacularly startKeepalive(mContext); Log.d(TAG, "Added Transform with Id " + mResourceId); mCloseGuard.open("build"); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } startKeepalive(mContext); // Will silently fail if not required mTransformId = transformId; Log.d(TAG, "Added Transform with Id " + transformId); } mCloseGuard.open("build"); return this; } Loading @@ -133,22 +168,28 @@ public final class IpSecTransform implements AutoCloseable { * transform is no longer needed. */ public void close() { Log.d(TAG, "Removing Transform with Id " + mTransformId); Log.d(TAG, "Removing Transform with Id " + mResourceId); // Always safe to attempt cleanup if (mTransformId == INVALID_TRANSFORM_ID) { if (mResourceId == INVALID_RESOURCE_ID) { mCloseGuard.close(); return; } //try { try { /* Order matters here because the keepalive is best-effort but could fail in some * horrible way to be removed if the wifi (or cell) subsystem has crashed, and we * still want to clear out the transform. */ IIpSecService svc = getIpSecService(); svc.deleteTransportModeTransform(mResourceId); stopKeepalive(); //} catch (RemoteException e) { // transform.setTransformId(transformId); // throw e.rethrowFromSystemServer(); //} finally { mTransformId = INVALID_TRANSFORM_ID; //} } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } finally { mResourceId = INVALID_RESOURCE_ID; mCloseGuard.close(); } } @Override protected void finalize() throws Throwable { Loading @@ -164,7 +205,7 @@ public final class IpSecTransform implements AutoCloseable { } private final IpSecConfig mConfig; private int mTransformId; private int mResourceId; private final Context mContext; private final CloseGuard mCloseGuard = CloseGuard.get(); private ConnectivityManager.PacketKeepalive mKeepalive; Loading Loading @@ -200,6 +241,7 @@ public final class IpSecTransform implements AutoCloseable { /* Package */ void startKeepalive(Context c) { // FIXME: NO_KEEPALIVE needs to be a constant if (mConfig.getNattKeepaliveInterval() == 0) { return; } Loading @@ -208,7 +250,7 @@ public final class IpSecTransform implements AutoCloseable { (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE); if (mKeepalive != null) { Log.e(TAG, "Keepalive already started for this IpSecTransform."); Log.wtf(TAG, "Keepalive already started for this IpSecTransform."); return; } Loading @@ -218,10 +260,11 @@ public final class IpSecTransform implements AutoCloseable { mConfig.getNetwork(), mConfig.getNattKeepaliveInterval(), mKeepaliveCallback, mConfig.getLocalIp(), mConfig.getLocalAddress(), mConfig.getEncapLocalPort(), mConfig.getRemoteIp()); mConfig.getRemoteAddress()); try { // FIXME: this is still a horrible way to fudge the synchronous callback mKeepaliveSyncLock.wait(2000); } catch (InterruptedException e) { } Loading @@ -231,6 +274,11 @@ public final class IpSecTransform implements AutoCloseable { } } /* Package */ int getResourceId() { return mResourceId; } /* Package */ void stopKeepalive() { if (mKeepalive == null) { Loading @@ -247,16 +295,6 @@ public final class IpSecTransform implements AutoCloseable { } } /* Package */ void setTransformId(int transformId) { mTransformId = transformId; } /* Package */ int getTransformId() { return mTransformId; } /** * Builder object to facilitate the creation of IpSecTransform objects. * Loading @@ -280,7 +318,7 @@ public final class IpSecTransform implements AutoCloseable { */ public IpSecTransform.Builder setEncryption( @TransformDirection int direction, IpSecAlgorithm algo) { mConfig.flow[direction].encryptionAlgo = algo; mConfig.flow[direction].encryption = algo; return this; } Loading @@ -295,7 +333,7 @@ public final class IpSecTransform implements AutoCloseable { */ public IpSecTransform.Builder setAuthentication( @TransformDirection int direction, IpSecAlgorithm algo) { mConfig.flow[direction].authenticationAlgo = algo; mConfig.flow[direction].authentication = algo; return this; } Loading @@ -318,6 +356,8 @@ public final class IpSecTransform implements AutoCloseable { */ public IpSecTransform.Builder setSpi( @TransformDirection int direction, IpSecManager.SecurityParameterIndex spi) { // TODO: convert to using the resource Id of the SPI. Then build() can validate // the owner in the IpSecService mConfig.flow[direction].spi = spi.getSpi(); return this; } Loading Loading @@ -439,7 +479,8 @@ public final class IpSecTransform implements AutoCloseable { * * @param context current Context */ public Builder(Context context) { public Builder(@NonNull Context context) { Preconditions.checkNotNull(context); mContext = context; mConfig = new IpSecConfig(); } Loading Loading
core/java/android/net/IIpSecService.aidl +22 −0 Original line number Diff line number Diff line Loading @@ -16,9 +16,31 @@ package android.net; import android.net.Network; import android.net.IpSecConfig; import android.os.Bundle; import android.os.IBinder; import android.os.ParcelFileDescriptor; /** * @hide */ interface IIpSecService { Bundle reserveSecurityParameterIndex( int direction, in String remoteAddress, int requestedSpi, in IBinder binder); void releaseSecurityParameterIndex(int resourceId); Bundle openUdpEncapsulationSocket(int port, in IBinder binder); void closeUdpEncapsulationSocket(in ParcelFileDescriptor socket); Bundle createTransportModeTransform(in IpSecConfig c, in IBinder binder); void deleteTransportModeTransform(int transformId); void applyTransportModeTransform(in ParcelFileDescriptor socket, int transformId); void removeTransportModeTransform(in ParcelFileDescriptor socket, int transformId); }
core/java/android/net/IpSecAlgorithm.java +2 −0 Original line number Diff line number Diff line Loading @@ -164,6 +164,8 @@ public final class IpSecAlgorithm implements Parcelable { private static boolean isTruncationLengthValid(String algo, int truncLenBits) { switch (algo) { case ALGO_CRYPT_AES_CBC: return (truncLenBits == 128 || truncLenBits == 192 || truncLenBits == 256); case ALGO_AUTH_HMAC_MD5: return (truncLenBits >= 96 && truncLenBits <= 128); case ALGO_AUTH_HMAC_SHA1: Loading
core/java/android/net/IpSecConfig.java +26 −44 Original line number Diff line number Diff line Loading @@ -23,7 +23,7 @@ import java.net.UnknownHostException; /** @hide */ public final class IpSecConfig implements Parcelable { private static final String TAG = IpSecConfig.class.getSimpleName(); private static final String TAG = "IpSecConfig"; //MODE_TRANSPORT or MODE_TUNNEL int mode; Loading @@ -43,13 +43,13 @@ public final class IpSecConfig implements Parcelable { int spi; // Encryption Algorithm IpSecAlgorithm encryptionAlgo; IpSecAlgorithm encryption; // Authentication Algorithm IpSecAlgorithm authenticationAlgo; IpSecAlgorithm authentication; } Flow[] flow = new Flow[2]; Flow[] flow = new Flow[] {new Flow(), new Flow()}; // For tunnel mode IPv4 UDP Encapsulation // IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE Loading @@ -57,17 +57,15 @@ public final class IpSecConfig implements Parcelable { int encapLocalPort; int encapRemotePort; // An optional protocol to match with the selector int selectorProto; // A bitmask of FEATURE_* indicating which of the fields // of this class are valid. long features; // An interval, in seconds between the NattKeepalive packets int nattKeepaliveInterval; public InetAddress getLocalIp() { // Transport or Tunnel public int getMode() { return mode; } public InetAddress getLocalAddress() { return localAddress; } Loading @@ -75,19 +73,19 @@ public final class IpSecConfig implements Parcelable { return flow[direction].spi; } public InetAddress getRemoteIp() { public InetAddress getRemoteAddress() { return remoteAddress; } public IpSecAlgorithm getEncryptionAlgo(int direction) { return flow[direction].encryptionAlgo; public IpSecAlgorithm getEncryption(int direction) { return flow[direction].encryption; } public IpSecAlgorithm getAuthenticationAlgo(int direction) { return flow[direction].authenticationAlgo; public IpSecAlgorithm getAuthentication(int direction) { return flow[direction].authentication; } Network getNetwork() { public Network getNetwork() { return network; } Loading @@ -103,18 +101,10 @@ public final class IpSecConfig implements Parcelable { return encapRemotePort; } public int getSelectorProto() { return selectorProto; } int getNattKeepaliveInterval() { public int getNattKeepaliveInterval() { return nattKeepaliveInterval; } public boolean hasProperty(int featureBits) { return (features & featureBits) == featureBits; } // Parcelable Methods @Override Loading @@ -124,31 +114,25 @@ public final class IpSecConfig implements Parcelable { @Override public void writeToParcel(Parcel out, int flags) { out.writeLong(features); // TODO: Use a byte array or other better method for storing IPs that can also include scope out.writeString((localAddress != null) ? localAddress.getHostAddress() : null); // TODO: Use a byte array or other better method for storing IPs that can also include scope out.writeString((remoteAddress != null) ? remoteAddress.getHostAddress() : null); out.writeParcelable(network, flags); out.writeInt(flow[IpSecTransform.DIRECTION_IN].spi); out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryptionAlgo, flags); out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authenticationAlgo, flags); out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryption, flags); out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authentication, flags); out.writeInt(flow[IpSecTransform.DIRECTION_OUT].spi); out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo, flags); out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo, flags); out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryption, flags); out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authentication, flags); out.writeInt(encapType); out.writeInt(encapLocalPort); out.writeInt(encapRemotePort); out.writeInt(selectorProto); } // Package Private: Used by the IpSecTransform.Builder; // there should be no public constructor for this object IpSecConfig() { flow[IpSecTransform.DIRECTION_IN].spi = 0; flow[IpSecTransform.DIRECTION_OUT].spi = 0; nattKeepaliveInterval = 0; //FIXME constant } IpSecConfig() {} private static InetAddress readInetAddressFromParcel(Parcel in) { String addrString = in.readString(); Loading @@ -164,24 +148,22 @@ public final class IpSecConfig implements Parcelable { } private IpSecConfig(Parcel in) { features = in.readLong(); localAddress = readInetAddressFromParcel(in); remoteAddress = readInetAddressFromParcel(in); network = (Network) in.readParcelable(Network.class.getClassLoader()); flow[IpSecTransform.DIRECTION_IN].spi = in.readInt(); flow[IpSecTransform.DIRECTION_IN].encryptionAlgo = flow[IpSecTransform.DIRECTION_IN].encryption = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); flow[IpSecTransform.DIRECTION_IN].authenticationAlgo = flow[IpSecTransform.DIRECTION_IN].authentication = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); flow[IpSecTransform.DIRECTION_OUT].spi = in.readInt(); flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo = flow[IpSecTransform.DIRECTION_OUT].encryption = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo = flow[IpSecTransform.DIRECTION_OUT].authentication = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); encapType = in.readInt(); encapLocalPort = in.readInt(); encapRemotePort = in.readInt(); selectorProto = in.readInt(); } public static final Parcelable.Creator<IpSecConfig> CREATOR = Loading
core/java/android/net/IpSecManager.java +90 −22 Original line number Diff line number Diff line Loading @@ -17,8 +17,11 @@ package android.net; import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.SystemApi; import android.annotation.NonNull; import android.os.Binder; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.AndroidException; import dalvik.system.CloseGuard; import java.io.FileDescriptor; Loading @@ -38,6 +41,29 @@ import java.net.Socket; public final class IpSecManager { private static final String TAG = "IpSecManager"; /** * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index. * * <p>No IPsec packet may contain an SPI of 0. */ public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; /** @hide */ public interface Status { public static final int OK = 0; public static final int RESOURCE_UNAVAILABLE = 1; public static final int SPI_UNAVAILABLE = 2; } /** @hide */ public static final String KEY_STATUS = "status"; /** @hide */ public static final String KEY_RESOURCE_ID = "resourceId"; /** @hide */ public static final String KEY_SPI = "spi"; /** @hide */ public static final int INVALID_RESOURCE_ID = 0; /** * Indicates that the combination of remote InetAddress and SPI was non-unique for a given * request. If encountered, selection of a new SPI is required before a transform may be Loading Loading @@ -83,22 +109,14 @@ public final class IpSecManager { private final IIpSecService mService; private final InetAddress mRemoteAddress; private final CloseGuard mCloseGuard = CloseGuard.get(); private int mSpi; private int mSpi = INVALID_SECURITY_PARAMETER_INDEX; private int mResourceId; /** Return the underlying SPI held by this object */ public int getSpi() { return mSpi; } private SecurityParameterIndex( IIpSecService service, int direction, InetAddress remoteAddress, int spi) throws ResourceUnavailableException, SpiUnavailableException { mService = service; mRemoteAddress = remoteAddress; mSpi = spi; mCloseGuard.open("open"); } /** * Release an SPI that was previously reserved. * Loading @@ -108,7 +126,7 @@ public final class IpSecManager { */ @Override public void close() { mSpi = INVALID_SECURITY_PARAMETER_INDEX; // TODO: Invalid SPI mSpi = INVALID_SECURITY_PARAMETER_INDEX; mCloseGuard.close(); } Loading @@ -120,14 +138,52 @@ public final class IpSecManager { close(); } private SecurityParameterIndex( @NonNull IIpSecService service, int direction, InetAddress remoteAddress, int spi) throws ResourceUnavailableException, SpiUnavailableException { mService = service; mRemoteAddress = remoteAddress; try { Bundle result = mService.reserveSecurityParameterIndex( direction, remoteAddress.getHostAddress(), spi, new Binder()); if (result == null) { throw new NullPointerException("Received null response from IpSecService"); } int status = result.getInt(KEY_STATUS); switch (status) { case Status.OK: break; case Status.RESOURCE_UNAVAILABLE: throw new ResourceUnavailableException( "No more SPIs may be allocated by this requester."); case Status.SPI_UNAVAILABLE: throw new SpiUnavailableException("Requested SPI is unavailable", spi); default: throw new RuntimeException( "Unknown status returned by IpSecService: " + status); } mSpi = result.getInt(KEY_SPI); mResourceId = result.getInt(KEY_RESOURCE_ID); /** * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index. * * <p>No IPsec packet may contain an SPI of 0. */ public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; if (mSpi == INVALID_SECURITY_PARAMETER_INDEX) { throw new RuntimeException("Invalid SPI returned by IpSecService: " + status); } if (mResourceId == INVALID_RESOURCE_ID) { throw new RuntimeException( "Invalid Resource ID returned by IpSecService: " + status); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } mCloseGuard.open("open"); } } /** * Reserve an SPI for traffic bound towards the specified remote address. Loading Loading @@ -184,7 +240,13 @@ public final class IpSecManager { } /* Call down to activate a transform */ private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {} private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { try { mService.applyTransportModeTransform(pfd, transform.getResourceId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Apply an active Tunnel Mode IPsec Transform to a network, which will tunnel all traffic to Loading Loading @@ -228,7 +290,13 @@ public final class IpSecManager { } /* Call down to activate a transform */ private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {} private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { try { mService.removeTransportModeTransform(pfd, transform.getResourceId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of Loading @@ -255,7 +323,7 @@ public final class IpSecManager { private final IIpSecService mService; private final CloseGuard mCloseGuard = CloseGuard.get(); private UdpEncapsulationSocket(IIpSecService service, int port) private UdpEncapsulationSocket(@NonNull IIpSecService service, int port) throws ResourceUnavailableException { mService = service; mCloseGuard.open("constructor"); Loading
core/java/android/net/IpSecTransform.java +92 −51 Original line number Diff line number Diff line Loading @@ -15,11 +15,21 @@ */ package android.net; import static android.net.IpSecManager.INVALID_RESOURCE_ID; import static android.net.IpSecManager.KEY_RESOURCE_ID; import static android.net.IpSecManager.KEY_STATUS; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.content.Context; import android.system.ErrnoException; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import com.android.internal.util.Preconditions; import dalvik.system.CloseGuard; import java.io.IOException; import java.lang.annotation.Retention; Loading Loading @@ -86,39 +96,64 @@ public final class IpSecTransform implements AutoCloseable { @Retention(RetentionPolicy.SOURCE) public @interface EncapType {} /** * Sentinel for an invalid transform (means that this transform is inactive). * * @hide */ public static final int INVALID_TRANSFORM_ID = -1; private IpSecTransform(Context context, IpSecConfig config) { mContext = context; mConfig = config; mTransformId = INVALID_TRANSFORM_ID; mResourceId = INVALID_RESOURCE_ID; } private IIpSecService getIpSecService() { IBinder b = ServiceManager.getService(android.content.Context.IPSEC_SERVICE); if (b == null) { throw new RemoteException("Failed to connect to IpSecService") .rethrowAsRuntimeException(); } return IIpSecService.Stub.asInterface(b); } private void checkResultStatusAndThrow(int status) throws IOException, IpSecManager.ResourceUnavailableException, IpSecManager.SpiUnavailableException { switch (status) { case IpSecManager.Status.OK: return; // TODO: Pass Error string back from bundle so that errors can be more specific case IpSecManager.Status.RESOURCE_UNAVAILABLE: throw new IpSecManager.ResourceUnavailableException( "Failed to allocate a new IpSecTransform"); case IpSecManager.Status.SPI_UNAVAILABLE: Log.wtf(TAG, "Attempting to use an SPI that was somehow not reserved"); // Fall through default: throw new IllegalStateException( "Failed to Create a Transform with status code " + status); } } private IpSecTransform activate() throws IOException, IpSecManager.ResourceUnavailableException, IpSecManager.SpiUnavailableException { int transformId; synchronized (this) { //try { transformId = INVALID_TRANSFORM_ID; //} catch (RemoteException e) { // throw e.rethrowFromSystemServer(); //} if (transformId < 0) { throw new ErrnoException("addTransform", -transformId).rethrowAsIOException(); try { IIpSecService svc = getIpSecService(); Bundle result = svc.createTransportModeTransform(mConfig, new Binder()); int status = result.getInt(KEY_STATUS); checkResultStatusAndThrow(status); mResourceId = result.getInt(KEY_RESOURCE_ID, INVALID_RESOURCE_ID); /* Keepalive will silently fail if not needed by the config; but, if needed and * it fails to start, we need to bail because a transform will not be reliable * to use if keepalive is expected to offload and fails. */ // FIXME: if keepalive fails, we need to fail spectacularly startKeepalive(mContext); Log.d(TAG, "Added Transform with Id " + mResourceId); mCloseGuard.open("build"); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } startKeepalive(mContext); // Will silently fail if not required mTransformId = transformId; Log.d(TAG, "Added Transform with Id " + transformId); } mCloseGuard.open("build"); return this; } Loading @@ -133,22 +168,28 @@ public final class IpSecTransform implements AutoCloseable { * transform is no longer needed. */ public void close() { Log.d(TAG, "Removing Transform with Id " + mTransformId); Log.d(TAG, "Removing Transform with Id " + mResourceId); // Always safe to attempt cleanup if (mTransformId == INVALID_TRANSFORM_ID) { if (mResourceId == INVALID_RESOURCE_ID) { mCloseGuard.close(); return; } //try { try { /* Order matters here because the keepalive is best-effort but could fail in some * horrible way to be removed if the wifi (or cell) subsystem has crashed, and we * still want to clear out the transform. */ IIpSecService svc = getIpSecService(); svc.deleteTransportModeTransform(mResourceId); stopKeepalive(); //} catch (RemoteException e) { // transform.setTransformId(transformId); // throw e.rethrowFromSystemServer(); //} finally { mTransformId = INVALID_TRANSFORM_ID; //} } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } finally { mResourceId = INVALID_RESOURCE_ID; mCloseGuard.close(); } } @Override protected void finalize() throws Throwable { Loading @@ -164,7 +205,7 @@ public final class IpSecTransform implements AutoCloseable { } private final IpSecConfig mConfig; private int mTransformId; private int mResourceId; private final Context mContext; private final CloseGuard mCloseGuard = CloseGuard.get(); private ConnectivityManager.PacketKeepalive mKeepalive; Loading Loading @@ -200,6 +241,7 @@ public final class IpSecTransform implements AutoCloseable { /* Package */ void startKeepalive(Context c) { // FIXME: NO_KEEPALIVE needs to be a constant if (mConfig.getNattKeepaliveInterval() == 0) { return; } Loading @@ -208,7 +250,7 @@ public final class IpSecTransform implements AutoCloseable { (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE); if (mKeepalive != null) { Log.e(TAG, "Keepalive already started for this IpSecTransform."); Log.wtf(TAG, "Keepalive already started for this IpSecTransform."); return; } Loading @@ -218,10 +260,11 @@ public final class IpSecTransform implements AutoCloseable { mConfig.getNetwork(), mConfig.getNattKeepaliveInterval(), mKeepaliveCallback, mConfig.getLocalIp(), mConfig.getLocalAddress(), mConfig.getEncapLocalPort(), mConfig.getRemoteIp()); mConfig.getRemoteAddress()); try { // FIXME: this is still a horrible way to fudge the synchronous callback mKeepaliveSyncLock.wait(2000); } catch (InterruptedException e) { } Loading @@ -231,6 +274,11 @@ public final class IpSecTransform implements AutoCloseable { } } /* Package */ int getResourceId() { return mResourceId; } /* Package */ void stopKeepalive() { if (mKeepalive == null) { Loading @@ -247,16 +295,6 @@ public final class IpSecTransform implements AutoCloseable { } } /* Package */ void setTransformId(int transformId) { mTransformId = transformId; } /* Package */ int getTransformId() { return mTransformId; } /** * Builder object to facilitate the creation of IpSecTransform objects. * Loading @@ -280,7 +318,7 @@ public final class IpSecTransform implements AutoCloseable { */ public IpSecTransform.Builder setEncryption( @TransformDirection int direction, IpSecAlgorithm algo) { mConfig.flow[direction].encryptionAlgo = algo; mConfig.flow[direction].encryption = algo; return this; } Loading @@ -295,7 +333,7 @@ public final class IpSecTransform implements AutoCloseable { */ public IpSecTransform.Builder setAuthentication( @TransformDirection int direction, IpSecAlgorithm algo) { mConfig.flow[direction].authenticationAlgo = algo; mConfig.flow[direction].authentication = algo; return this; } Loading @@ -318,6 +356,8 @@ public final class IpSecTransform implements AutoCloseable { */ public IpSecTransform.Builder setSpi( @TransformDirection int direction, IpSecManager.SecurityParameterIndex spi) { // TODO: convert to using the resource Id of the SPI. Then build() can validate // the owner in the IpSecService mConfig.flow[direction].spi = spi.getSpi(); return this; } Loading Loading @@ -439,7 +479,8 @@ public final class IpSecTransform implements AutoCloseable { * * @param context current Context */ public Builder(Context context) { public Builder(@NonNull Context context) { Preconditions.checkNotNull(context); mContext = context; mConfig = new IpSecConfig(); } Loading