11afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold/* 21afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * Copyright (C) 2017 The Android Open Source Project 31afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * 41afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * Licensed under the Apache License, Version 2.0 (the "License"); 51afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * you may not use this file except in compliance with the License. 61afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * You may obtain a copy of the License at 71afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * 81afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * http://www.apache.org/licenses/LICENSE-2.0 91afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * 101afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * Unless required by applicable law or agreed to in writing, software 111afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * distributed under the License is distributed on an "AS IS" BASIS, 121afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * See the License for the specific language governing permissions and 141afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * limitations under the License. 151afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold */ 161afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold 171afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldpackage com.android.server; 181afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold 191afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldimport static android.Manifest.permission.DUMP; 2093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport static android.net.IpSecManager.INVALID_RESOURCE_ID; 218dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport static android.system.OsConstants.AF_INET; 228dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport static android.system.OsConstants.IPPROTO_UDP; 238dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport static android.system.OsConstants.SOCK_DGRAM; 248dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport static com.android.internal.util.Preconditions.checkNotNull; 251afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold 261afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldimport android.content.Context; 271afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldimport android.net.IIpSecService; 281afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldimport android.net.INetd; 2993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.net.IpSecAlgorithm; 3093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.net.IpSecConfig; 3193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.net.IpSecManager; 328dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport android.net.IpSecSpiResponse; 3393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.net.IpSecTransform; 348dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport android.net.IpSecTransformResponse; 358dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport android.net.IpSecUdpEncapResponse; 361afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldimport android.net.util.NetdService; 3793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.os.Binder; 3893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.os.IBinder; 3993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.os.ParcelFileDescriptor; 401afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldimport android.os.RemoteException; 4193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.os.ServiceSpecificException; 428dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport android.system.ErrnoException; 438dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport android.system.Os; 448dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport android.system.OsConstants; 451afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldimport android.util.Log; 461afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldimport android.util.Slog; 4793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.util.SparseArray; 4893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport com.android.internal.annotations.GuardedBy; 491afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldimport java.io.FileDescriptor; 508dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport java.io.IOException; 511afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldimport java.io.PrintWriter; 528dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport java.net.InetAddress; 538dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport java.net.InetSocketAddress; 548dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport java.net.UnknownHostException; 5593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport java.util.concurrent.atomic.AtomicInteger; 568dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport libcore.io.IoUtils; 571afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold 581afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold/** @hide */ 591afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldpublic class IpSecService extends IIpSecService.Stub { 601afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold private static final String TAG = "IpSecService"; 611afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); 628dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 631afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold private static final String NETD_SERVICE_NAME = "netd"; 6493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold private static final int[] DIRECTIONS = 6593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold new int[] {IpSecTransform.DIRECTION_OUT, IpSecTransform.DIRECTION_IN}; 661afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold 678dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private static final int NETD_FETCH_TIMEOUT = 5000; //ms 688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private static final int MAX_PORT_BIND_ATTEMPTS = 10; 698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private static final InetAddress INADDR_ANY; 708dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 718dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold static { 728dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold try { 738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0}); 748dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } catch (UnknownHostException e) { 758dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold throw new RuntimeException(e); 768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 788dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 798dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold static final int FREE_PORT_MIN = 1024; // ports 1-1023 are reserved 808dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold static final int PORT_MAX = 0xFFFF; // ports are an unsigned 16-bit integer 818dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 828dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold /* Binder context for this service */ 831afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold private final Context mContext; 841afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold 858dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold /** Should be a never-repeating global ID for resources */ 868dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private static AtomicInteger mNextResourceId = new AtomicInteger(0x00FADED0); 871afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold 888dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold @GuardedBy("this") 898dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private final ManagedResourceArray<SpiRecord> mSpiRecords = new ManagedResourceArray<>(); 908dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 918dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold @GuardedBy("this") 928dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private final ManagedResourceArray<TransformRecord> mTransformRecords = 938dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold new ManagedResourceArray<>(); 941afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold 958dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold @GuardedBy("this") 968dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private final ManagedResourceArray<UdpSocketRecord> mUdpSocketRecords = 978dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold new ManagedResourceArray<>(); 9893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 998dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold /** 1008dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * The ManagedResource class provides a facility to cleanly and reliably release system 1018dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * resources. It relies on two things: an IBinder that allows ManagedResource to automatically 1028dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * clean up in the event that the Binder dies and a user-provided resourceId that should 1038dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * uniquely identify the managed resource. To use this class, the user should implement the 1048dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * releaseResources() method that is responsible for releasing system resources when invoked. 1058dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold */ 10693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold private abstract class ManagedResource implements IBinder.DeathRecipient { 10793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold final int pid; 10893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold final int uid; 10993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold private IBinder mBinder; 1108dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold protected int mResourceId; 1118dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 1128dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private AtomicInteger mReferenceCount = new AtomicInteger(0); 11393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 1148dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold ManagedResource(int resourceId, IBinder binder) { 11593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold super(); 11693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold mBinder = binder; 1178dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mResourceId = resourceId; 11893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold pid = Binder.getCallingPid(); 11993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold uid = Binder.getCallingUid(); 12093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 12193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold try { 12293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold mBinder.linkToDeath(this, 0); 12393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } catch (RemoteException e) { 12493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold binderDied(); 12593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 12693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 12793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 1288dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public void addReference() { 1298dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mReferenceCount.incrementAndGet(); 1308dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 1318dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 1328dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public void removeReference() { 1338dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (mReferenceCount.decrementAndGet() < 0) { 1348dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold Log.wtf(TAG, "Programming error: negative reference count"); 1358dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 1368dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 1378dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 1388dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public boolean isReferenced() { 1398dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return (mReferenceCount.get() > 0); 1408dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 1418dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 1428dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public void checkOwnerOrSystemAndThrow() { 1438dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (uid != Binder.getCallingUid() 1448dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold && android.os.Process.SYSTEM_UID != Binder.getCallingUid()) { 1458dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold throw new SecurityException("Only the owner may access managed resources!"); 1468dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 1478dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 1488dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 14993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold /** 15093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * When this record is no longer needed for managing system resources this function should 1518dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * clean up all system resources and nullify the record. This function shall perform all 1528dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * necessary cleanup of the resources managed by this record. 1538dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * 1548dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * <p>NOTE: this function verifies ownership before allowing resources to be freed. 15593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold */ 1568dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public final void release() throws RemoteException { 1578dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold synchronized (IpSecService.this) { 1588dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (isReferenced()) { 1598dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold throw new IllegalStateException( 1608dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold "Cannot release a resource that has active references!"); 1618dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 16293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 1638dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (mResourceId == INVALID_RESOURCE_ID) { 1648dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return; 1658dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 1668dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 1678dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold releaseResources(); 1688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (mBinder != null) { 1698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mBinder.unlinkToDeath(this, 0); 1708dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 1718dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mBinder = null; 17293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 1738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mResourceId = INVALID_RESOURCE_ID; 1748dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 17593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 17693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 17793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold /** 17893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * If the Binder object dies, this function is called to free the system resources that are 17993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * being managed by this record and to subsequently release this record for garbage 18093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * collection 18193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold */ 18293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold public final void binderDied() { 1838dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold try { 1848dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold release(); 1858dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } catch (Exception e) { 1868dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold Log.e(TAG, "Failed to release resource: " + e); 1878dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 18893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 18993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 19093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold /** 19193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * Implement this method to release all system resources that are being protected by this 19293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * record. Once the resources are released, the record should be invalidated and no longer 1938dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * used by calling release(). This should NEVER be called directly. 1948dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * 1958dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * <p>Calls to this are always guarded by IpSecService#this 19693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold */ 1978dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold protected abstract void releaseResources() throws RemoteException; 19893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold }; 19993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 2008dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold /** 2018dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * Minimal wrapper around SparseArray that performs ownership 2028dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * validation on element accesses. 2038dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold */ 2048dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private class ManagedResourceArray<T extends ManagedResource> { 2058dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold SparseArray<T> mArray = new SparseArray<>(); 2068dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 2078dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold T get(int key) { 2088dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold T val = mArray.get(key); 209b6d2eff8b1ad4ceed1f8a97f19e43aff5452898fNathan Harold // The value should never be null unless the resource doesn't exist 210b6d2eff8b1ad4ceed1f8a97f19e43aff5452898fNathan Harold // (since we do not allow null resources to be added). 211b6d2eff8b1ad4ceed1f8a97f19e43aff5452898fNathan Harold if (val != null) { 212b6d2eff8b1ad4ceed1f8a97f19e43aff5452898fNathan Harold val.checkOwnerOrSystemAndThrow(); 213b6d2eff8b1ad4ceed1f8a97f19e43aff5452898fNathan Harold } 2148dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return val; 2158dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 2168dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 2178dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold void put(int key, T obj) { 2188dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold checkNotNull(obj, "Null resources cannot be added"); 2198dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mArray.put(key, obj); 2208dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 2218dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 2228dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold void remove(int key) { 2238dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mArray.remove(key); 2248dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 2258dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 2268dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 22793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold private final class TransformRecord extends ManagedResource { 2288dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private final IpSecConfig mConfig; 2298dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private final SpiRecord[] mSpis; 2308dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private final UdpSocketRecord mSocket; 23193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 2328dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold TransformRecord( 2338dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold int resourceId, 2348dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold IBinder binder, 2358dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold IpSecConfig config, 2368dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold SpiRecord[] spis, 2378dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold UdpSocketRecord socket) { 2388dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold super(resourceId, binder); 23993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold mConfig = config; 2408dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mSpis = spis; 2418dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mSocket = socket; 2428dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 2438dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold for (int direction : DIRECTIONS) { 2448dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mSpis[direction].addReference(); 2458dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mSpis[direction].setOwnedByTransform(); 2468dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 2478dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 2488dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (mSocket != null) { 2498dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mSocket.addReference(); 2508dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 25193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 25293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 25393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold public IpSecConfig getConfig() { 25493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold return mConfig; 25593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 25693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 2578dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public SpiRecord getSpiRecord(int direction) { 2588dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return mSpis[direction]; 2598dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 2608dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 2618dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold /** always guarded by IpSecService#this */ 26293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold @Override 26393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold protected void releaseResources() { 26493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold for (int direction : DIRECTIONS) { 2658dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold int spi = mSpis[direction].getSpi(); 26693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold try { 26793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold getNetdInstance() 26893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold .ipSecDeleteSecurityAssociation( 26993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold mResourceId, 27093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold direction, 27193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold (mConfig.getLocalAddress() != null) 27293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold ? mConfig.getLocalAddress().getHostAddress() 27393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold : "", 27493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold (mConfig.getRemoteAddress() != null) 27593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold ? mConfig.getRemoteAddress().getHostAddress() 27693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold : "", 2778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold spi); 27893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } catch (ServiceSpecificException e) { 27993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold // FIXME: get the error code and throw is at an IOException from Errno Exception 28093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } catch (RemoteException e) { 28193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold Log.e(TAG, "Failed to delete SA with ID: " + mResourceId); 28293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 28393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 28493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 2858dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold for (int direction : DIRECTIONS) { 2868dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mSpis[direction].removeReference(); 2878dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 2888dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 2898dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (mSocket != null) { 2908dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mSocket.removeReference(); 2918dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 29293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 29393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 29493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 29593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold private final class SpiRecord extends ManagedResource { 29693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold private final int mDirection; 29793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold private final String mLocalAddress; 29893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold private final String mRemoteAddress; 29993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold private int mSpi; 3008dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 3018dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private boolean mOwnedByTransform = false; 30293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 30393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold SpiRecord( 30493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold int resourceId, 3058dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold IBinder binder, 30693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold int direction, 30793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold String localAddress, 30893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold String remoteAddress, 3098dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold int spi) { 3108dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold super(resourceId, binder); 31193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold mDirection = direction; 31293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold mLocalAddress = localAddress; 31393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold mRemoteAddress = remoteAddress; 31493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold mSpi = spi; 31593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 31693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 3178dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold /** always guarded by IpSecService#this */ 3188dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold @Override 31993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold protected void releaseResources() { 3208dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (mOwnedByTransform) { 3218dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold Log.d(TAG, "Cannot release Spi " + mSpi + ": Currently locked by a Transform"); 3228dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // Because SPIs are "handed off" to transform, objects, they should never be 3238dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // freed from the SpiRecord once used in a transform. (They refer to the same SA, 3248dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // thus ownership and responsibility for freeing these resources passes to the 3258dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // Transform object). Thus, we should let the user free them without penalty once 3268dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // they are applied in a Transform object. 3278dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return; 3288dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 3298dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 33093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold try { 33193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold getNetdInstance() 33293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold .ipSecDeleteSecurityAssociation( 33393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold mResourceId, mDirection, mLocalAddress, mRemoteAddress, mSpi); 33493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } catch (ServiceSpecificException e) { 33593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold // FIXME: get the error code and throw is at an IOException from Errno Exception 33693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } catch (RemoteException e) { 33793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId); 33893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 33993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 34093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; 3418dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 3428dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 3438dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public int getSpi() { 3448dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return mSpi; 3458dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 3468dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 3478dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public void setOwnedByTransform() { 3488dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (mOwnedByTransform) { 3498dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // Programming error 350d6d8e452c15cd7f7020891601e41a9561dedc468Andreas Gampe throw new IllegalStateException("Cannot own an SPI twice!"); 3518dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 3528dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 3538dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mOwnedByTransform = true; 35493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 35593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 35693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 3578dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private final class UdpSocketRecord extends ManagedResource { 3588dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private FileDescriptor mSocket; 3598dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private final int mPort; 3608dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 3618dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold UdpSocketRecord(int resourceId, IBinder binder, FileDescriptor socket, int port) { 3628dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold super(resourceId, binder); 3638dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mSocket = socket; 3648dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mPort = port; 3658dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 3668dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 3678dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold /** always guarded by IpSecService#this */ 3688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold @Override 3698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold protected void releaseResources() { 3708dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold Log.d(TAG, "Closing port " + mPort); 3718dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold IoUtils.closeQuietly(mSocket); 3728dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mSocket = null; 3738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 3748dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 3758dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public int getPort() { 3768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return mPort; 3778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 37893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 3798dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public FileDescriptor getSocket() { 3808dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return mSocket; 3818dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 3828dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 38393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 3841afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold /** 3851afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * Constructs a new IpSecService instance 3861afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * 3871afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * @param context Binder context for this service 3881afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold */ 3891afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold private IpSecService(Context context) { 3901afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold mContext = context; 3911afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 3921afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold 3931afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold static IpSecService create(Context context) throws InterruptedException { 3941afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold final IpSecService service = new IpSecService(context); 3951afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold service.connectNativeNetdService(); 3961afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold return service; 3971afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 3981afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold 3991afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold public void systemReady() { 4001afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold if (isNetdAlive()) { 4011afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold Slog.d(TAG, "IpSecService is ready"); 4021afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } else { 4031afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold Slog.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!"); 4041afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 4051afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 4061afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold 4071afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold private void connectNativeNetdService() { 4081afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold // Avoid blocking the system server to do this 409b0e0508582c8f1cbee74ffbf11b8409dd28934e8Nathan Harold new Thread() { 410b0e0508582c8f1cbee74ffbf11b8409dd28934e8Nathan Harold @Override 411b0e0508582c8f1cbee74ffbf11b8409dd28934e8Nathan Harold public void run() { 412b0e0508582c8f1cbee74ffbf11b8409dd28934e8Nathan Harold synchronized (IpSecService.this) { 413b0e0508582c8f1cbee74ffbf11b8409dd28934e8Nathan Harold NetdService.get(NETD_FETCH_TIMEOUT); 414b0e0508582c8f1cbee74ffbf11b8409dd28934e8Nathan Harold } 415b0e0508582c8f1cbee74ffbf11b8409dd28934e8Nathan Harold } 416b0e0508582c8f1cbee74ffbf11b8409dd28934e8Nathan Harold }.start(); 4171afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 4181afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold 41993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold INetd getNetdInstance() throws RemoteException { 4201afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold final INetd netd = NetdService.getInstance(); 4211afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold if (netd == null) { 42293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold throw new RemoteException("Failed to Get Netd Instance"); 4231afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 4241afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold return netd; 4251afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 4261afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold 4278dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold synchronized boolean isNetdAlive() { 4288dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold try { 4298dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold final INetd netd = getNetdInstance(); 4308dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (netd == null) { 4311afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold return false; 4321afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 4338dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return netd.isAlive(); 4348dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } catch (RemoteException re) { 4358dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return false; 4361afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 4371afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 4381afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold 4391afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold @Override 44093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold /** Get a new SPI and maintain the reservation in the system server */ 4418dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public synchronized IpSecSpiResponse reserveSecurityParameterIndex( 44293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold int direction, String remoteAddress, int requestedSpi, IBinder binder) 44393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold throws RemoteException { 44493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold int resourceId = mNextResourceId.getAndIncrement(); 44593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 44693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; 44793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold String localAddress = ""; 44893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold try { 44993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold spi = 45093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold getNetdInstance() 45193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold .ipSecAllocateSpi( 45293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold resourceId, 45393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold direction, 45493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold localAddress, 45593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold remoteAddress, 45693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold requestedSpi); 45793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold Log.d(TAG, "Allocated SPI " + spi); 4588dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mSpiRecords.put( 4598dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold resourceId, 4608dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold new SpiRecord(resourceId, binder, direction, localAddress, remoteAddress, spi)); 46193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } catch (ServiceSpecificException e) { 46293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold // TODO: Add appropriate checks when other ServiceSpecificException types are supported 4638dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return new IpSecSpiResponse( 4648dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold IpSecManager.Status.SPI_UNAVAILABLE, IpSecManager.INVALID_RESOURCE_ID, spi); 46593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } catch (RemoteException e) { 46693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold throw e.rethrowFromSystemServer(); 46793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 4688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, spi); 4698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 4708dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 4718dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold /* This method should only be called from Binder threads. Do not call this from 4728dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * within the system server as it will crash the system on failure. 4738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold */ 4748dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private synchronized <T extends ManagedResource> void releaseManagedResource( 4758dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold ManagedResourceArray<T> resArray, int resourceId, String typeName) 4768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold throws RemoteException { 4778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // We want to non-destructively get so that we can check credentials before removing 4788dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // this from the records. 4798dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold T record = resArray.get(resourceId); 4808dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 4818dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (record == null) { 4828dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold throw new IllegalArgumentException( 4838dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold typeName + " " + resourceId + " is not available to be deleted"); 4848dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 4858dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 4868dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold record.release(); 4878dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold resArray.remove(resourceId); 48893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 48993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 49093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold /** Release a previously allocated SPI that has been registered with the system server */ 49193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold @Override 4928dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public void releaseSecurityParameterIndex(int resourceId) throws RemoteException { 4938dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold releaseManagedResource(mSpiRecords, resourceId, "SecurityParameterIndex"); 4948dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 4958dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 4968dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold /** 4978dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * This function finds and forcibly binds to a random system port, ensuring that the port cannot 4988dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * be unbound. 4998dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * 5008dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * <p>A socket cannot be un-bound from a port if it was bound to that port by number. To select 5018dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * a random open port and then bind by number, this function creates a temp socket, binds to a 5028dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * random port (specifying 0), gets that port number, and then uses is to bind the user's UDP 5038dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * Encapsulation Socket forcibly, so that it cannot be un-bound by the user with the returned 5048dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * FileHandle. 5058dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * 5068dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * <p>The loop in this function handles the inherent race window between un-binding to a port 5078dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * and re-binding, during which the system could *technically* hand that port out to someone 5088dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * else. 5098dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold */ 5108dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private void bindToRandomPort(FileDescriptor sockFd) throws IOException { 5118dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold for (int i = MAX_PORT_BIND_ATTEMPTS; i > 0; i--) { 5128dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold try { 5138dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold FileDescriptor probeSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 5148dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold Os.bind(probeSocket, INADDR_ANY, 0); 5158dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold int port = ((InetSocketAddress) Os.getsockname(probeSocket)).getPort(); 5168dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold Os.close(probeSocket); 5178dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold Log.v(TAG, "Binding to port " + port); 5188dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold Os.bind(sockFd, INADDR_ANY, port); 5198dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return; 5208dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } catch (ErrnoException e) { 5218dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // Someone miraculously claimed the port just after we closed probeSocket. 5228dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (e.errno == OsConstants.EADDRINUSE) { 5238dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold continue; 5248dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 5258dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold throw e.rethrowAsIOException(); 5268dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 5278dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 5288dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold throw new IOException("Failed " + MAX_PORT_BIND_ATTEMPTS + " attempts to bind to a port"); 5298dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 53093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 53193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold /** 53293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * Open a socket via the system server and bind it to the specified port (random if port=0). 53393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * This will return a PFD to the user that represent a bound UDP socket. The system server will 53493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * cache the socket and a record of its owner so that it can and must be freed when no longer 53593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * needed. 53693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold */ 53793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold @Override 5388dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public synchronized IpSecUdpEncapResponse openUdpEncapsulationSocket(int port, IBinder binder) 5398dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold throws RemoteException { 5408dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (port != 0 && (port < FREE_PORT_MIN || port > PORT_MAX)) { 5418dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold throw new IllegalArgumentException( 5428dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold "Specified port number must be a valid non-reserved UDP port"); 5438dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 5448dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold int resourceId = mNextResourceId.getAndIncrement(); 5458dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold FileDescriptor sockFd = null; 5468dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold try { 5478dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 5488dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 5498dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (port != 0) { 5508dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold Log.v(TAG, "Binding to port " + port); 5518dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold Os.bind(sockFd, INADDR_ANY, port); 5528dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } else { 5538dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold bindToRandomPort(sockFd); 5548dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 5558dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // This code is common to both the unspecified and specified port cases 5568dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold Os.setsockoptInt( 5578dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold sockFd, 5588dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold OsConstants.IPPROTO_UDP, 5598dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold OsConstants.UDP_ENCAP, 5608dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold OsConstants.UDP_ENCAP_ESPINUDP); 5618dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 5628dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mUdpSocketRecords.put( 5638dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold resourceId, new UdpSocketRecord(resourceId, binder, sockFd, port)); 5648dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return new IpSecUdpEncapResponse(IpSecManager.Status.OK, resourceId, port, sockFd); 5658dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } catch (IOException | ErrnoException e) { 5668dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold IoUtils.closeQuietly(sockFd); 5678dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 5688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // If we make it to here, then something has gone wrong and we couldn't open a socket. 5698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // The only reasonable condition that would cause that is resource unavailable. 5708dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return new IpSecUdpEncapResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); 57193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 57293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 57393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold /** close a socket that has been been allocated by and registered with the system server */ 57493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold @Override 5758dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public void closeUdpEncapsulationSocket(int resourceId) throws RemoteException { 5768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 5778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold releaseManagedResource(mUdpSocketRecords, resourceId, "UdpEncapsulationSocket"); 5788dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 57993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 58093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold /** 58193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * Create a transport mode transform, which represent two security associations (one in each 58293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * direction) in the kernel. The transform will be cached by the system server and must be freed 58393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * when no longer needed. It is possible to free one, deleting the SA from underneath sockets 58493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * that are using it, which will result in all of those sockets becoming unable to send or 58593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * receive data. 58693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold */ 58793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold @Override 5888dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public synchronized IpSecTransformResponse createTransportModeTransform( 5898dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold IpSecConfig c, IBinder binder) throws RemoteException { 59093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold int resourceId = mNextResourceId.getAndIncrement(); 5918dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold SpiRecord[] spis = new SpiRecord[DIRECTIONS.length]; 5928dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // TODO: Basic input validation here since it's coming over the Binder 5938dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold int encapType, encapLocalPort = 0, encapRemotePort = 0; 5948dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold UdpSocketRecord socketRecord = null; 5958dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold encapType = c.getEncapType(); 5968dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (encapType != IpSecTransform.ENCAP_NONE) { 5978dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold socketRecord = mUdpSocketRecords.get(c.getEncapLocalResourceId()); 5988dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold encapLocalPort = socketRecord.getPort(); 5998dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold encapRemotePort = c.getEncapRemotePort(); 6008dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 6018dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 60293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold for (int direction : DIRECTIONS) { 60393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold IpSecAlgorithm auth = c.getAuthentication(direction); 60493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold IpSecAlgorithm crypt = c.getEncryption(direction); 6058dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 6068dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold spis[direction] = mSpiRecords.get(c.getSpiResourceId(direction)); 6078dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold int spi = spis[direction].getSpi(); 60893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold try { 6090f807899b803a20ba1b0b047bf8c5c8717331508ludi getNetdInstance() 6100f807899b803a20ba1b0b047bf8c5c8717331508ludi .ipSecAddSecurityAssociation( 6110f807899b803a20ba1b0b047bf8c5c8717331508ludi resourceId, 6120f807899b803a20ba1b0b047bf8c5c8717331508ludi c.getMode(), 6130f807899b803a20ba1b0b047bf8c5c8717331508ludi direction, 6140f807899b803a20ba1b0b047bf8c5c8717331508ludi (c.getLocalAddress() != null) 6150f807899b803a20ba1b0b047bf8c5c8717331508ludi ? c.getLocalAddress().getHostAddress() 6160f807899b803a20ba1b0b047bf8c5c8717331508ludi : "", 6170f807899b803a20ba1b0b047bf8c5c8717331508ludi (c.getRemoteAddress() != null) 6180f807899b803a20ba1b0b047bf8c5c8717331508ludi ? c.getRemoteAddress().getHostAddress() 6190f807899b803a20ba1b0b047bf8c5c8717331508ludi : "", 6200f807899b803a20ba1b0b047bf8c5c8717331508ludi (c.getNetwork() != null) 6210f807899b803a20ba1b0b047bf8c5c8717331508ludi ? c.getNetwork().getNetworkHandle() 6220f807899b803a20ba1b0b047bf8c5c8717331508ludi : 0, 6230f807899b803a20ba1b0b047bf8c5c8717331508ludi spi, 6240f807899b803a20ba1b0b047bf8c5c8717331508ludi (auth != null) ? auth.getName() : "", 6250f807899b803a20ba1b0b047bf8c5c8717331508ludi (auth != null) ? auth.getKey() : null, 6260f807899b803a20ba1b0b047bf8c5c8717331508ludi (auth != null) ? auth.getTruncationLengthBits() : 0, 6270f807899b803a20ba1b0b047bf8c5c8717331508ludi (crypt != null) ? crypt.getName() : "", 6280f807899b803a20ba1b0b047bf8c5c8717331508ludi (crypt != null) ? crypt.getKey() : null, 6290f807899b803a20ba1b0b047bf8c5c8717331508ludi (crypt != null) ? crypt.getTruncationLengthBits() : 0, 6300f807899b803a20ba1b0b047bf8c5c8717331508ludi encapType, 6310f807899b803a20ba1b0b047bf8c5c8717331508ludi encapLocalPort, 6320f807899b803a20ba1b0b047bf8c5c8717331508ludi encapRemotePort); 63393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } catch (ServiceSpecificException e) { 63493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold // FIXME: get the error code and throw is at an IOException from Errno Exception 6350f807899b803a20ba1b0b047bf8c5c8717331508ludi return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); 63693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 63793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 6388dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // Both SAs were created successfully, time to construct a record and lock it away 6398dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mTransformRecords.put( 6408dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold resourceId, new TransformRecord(resourceId, binder, c, spis, socketRecord)); 6418dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return new IpSecTransformResponse(IpSecManager.Status.OK, resourceId); 64293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 64393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 64493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold /** 64593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * Delete a transport mode transform that was previously allocated by + registered with the 64693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * system server. If this is called on an inactive (or non-existent) transform, it will not 64793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * return an error. It's safe to de-allocate transforms that may have already been deleted for 64893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * other reasons. 64993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold */ 65093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold @Override 65193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold public void deleteTransportModeTransform(int resourceId) throws RemoteException { 6528dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold releaseManagedResource(mTransformRecords, resourceId, "IpSecTransform"); 65393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 65493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 65593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold /** 65693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * Apply an active transport mode transform to a socket, which will apply the IPsec security 65793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * association as a correspondent policy to the provided socket 65893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold */ 65993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold @Override 6608dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public synchronized void applyTransportModeTransform( 6618dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold ParcelFileDescriptor socket, int resourceId) throws RemoteException { 6628dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // Synchronize liberally here because we are using ManagedResources in this block 6638dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold TransformRecord info; 6648dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // FIXME: this code should be factored out into a security check + getter 6658dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold info = mTransformRecords.get(resourceId); 6668dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 6678dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (info == null) { 6688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold throw new IllegalArgumentException("Transform " + resourceId + " is not active"); 6698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 67093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 6718dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // TODO: make this a function. 6728dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (info.pid != getCallingPid() || info.uid != getCallingUid()) { 6738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold throw new SecurityException("Only the owner of an IpSec Transform may apply it!"); 6748dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 67593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 6768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold IpSecConfig c = info.getConfig(); 6778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold try { 6788dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold for (int direction : DIRECTIONS) { 6798dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold getNetdInstance() 6808dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold .ipSecApplyTransportModeTransform( 6818dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold socket.getFileDescriptor(), 6828dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold resourceId, 6838dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold direction, 6848dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold (c.getLocalAddress() != null) 6858dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold ? c.getLocalAddress().getHostAddress() 6868dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold : "", 6878dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold (c.getRemoteAddress() != null) 6888dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold ? c.getRemoteAddress().getHostAddress() 6898dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold : "", 6908dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold info.getSpiRecord(direction).getSpi()); 69193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 6928dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } catch (ServiceSpecificException e) { 6938dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // FIXME: get the error code and throw is at an IOException from Errno Exception 69493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 69593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 6968dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 69793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold /** 69893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * Remove a transport mode transform from a socket, applying the default (empty) policy. This 69993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * will ensure that NO IPsec policy is applied to the socket (would be the equivalent of 70093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * applying a policy that performs no IPsec). Today the resourceId parameter is passed but not 70193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * used: reserved for future improved input validation. 70293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold */ 70393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold @Override 70493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold public void removeTransportModeTransform(ParcelFileDescriptor socket, int resourceId) 70593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold throws RemoteException { 70693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold try { 70793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold getNetdInstance().ipSecRemoveTransportModeTransform(socket.getFileDescriptor()); 70893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } catch (ServiceSpecificException e) { 70993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold // FIXME: get the error code and throw is at an IOException from Errno Exception 71093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 71193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 71293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 71393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold @Override 7141afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 7151afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold mContext.enforceCallingOrSelfPermission(DUMP, TAG); 7168dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // TODO: Add dump code to print out a log of all the resources being tracked 7171afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold pw.println("IpSecService Log:"); 7181afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead")); 7191afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold pw.println(); 7201afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 7211afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold} 722