IpSecService.java revision d6d8e452c15cd7f7020891601e41a9561dedc468
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); 2098dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold val.checkOwnerOrSystemAndThrow(); 2108dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return val; 2118dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 2128dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 2138dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold void put(int key, T obj) { 2148dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold checkNotNull(obj, "Null resources cannot be added"); 2158dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mArray.put(key, obj); 2168dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 2178dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 2188dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold void remove(int key) { 2198dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mArray.remove(key); 2208dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 2218dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 2228dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 22393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold private final class TransformRecord extends ManagedResource { 2248dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private final IpSecConfig mConfig; 2258dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private final SpiRecord[] mSpis; 2268dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private final UdpSocketRecord mSocket; 22793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 2288dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold TransformRecord( 2298dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold int resourceId, 2308dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold IBinder binder, 2318dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold IpSecConfig config, 2328dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold SpiRecord[] spis, 2338dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold UdpSocketRecord socket) { 2348dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold super(resourceId, binder); 23593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold mConfig = config; 2368dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mSpis = spis; 2378dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mSocket = socket; 2388dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 2398dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold for (int direction : DIRECTIONS) { 2408dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mSpis[direction].addReference(); 2418dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mSpis[direction].setOwnedByTransform(); 2428dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 2438dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 2448dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (mSocket != null) { 2458dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mSocket.addReference(); 2468dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 24793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 24893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 24993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold public IpSecConfig getConfig() { 25093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold return mConfig; 25193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 25293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 2538dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public SpiRecord getSpiRecord(int direction) { 2548dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return mSpis[direction]; 2558dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 2568dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 2578dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold /** always guarded by IpSecService#this */ 25893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold @Override 25993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold protected void releaseResources() { 26093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold for (int direction : DIRECTIONS) { 2618dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold int spi = mSpis[direction].getSpi(); 26293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold try { 26393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold getNetdInstance() 26493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold .ipSecDeleteSecurityAssociation( 26593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold mResourceId, 26693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold direction, 26793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold (mConfig.getLocalAddress() != null) 26893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold ? mConfig.getLocalAddress().getHostAddress() 26993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold : "", 27093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold (mConfig.getRemoteAddress() != null) 27193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold ? mConfig.getRemoteAddress().getHostAddress() 27293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold : "", 2738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold spi); 27493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } catch (ServiceSpecificException e) { 27593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold // FIXME: get the error code and throw is at an IOException from Errno Exception 27693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } catch (RemoteException e) { 27793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold Log.e(TAG, "Failed to delete SA with ID: " + mResourceId); 27893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 27993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 28093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 2818dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold for (int direction : DIRECTIONS) { 2828dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mSpis[direction].removeReference(); 2838dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 2848dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 2858dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (mSocket != null) { 2868dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mSocket.removeReference(); 2878dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 28893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 28993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 29093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 29193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold private final class SpiRecord extends ManagedResource { 29293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold private final int mDirection; 29393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold private final String mLocalAddress; 29493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold private final String mRemoteAddress; 29593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold private int mSpi; 2968dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 2978dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private boolean mOwnedByTransform = false; 29893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 29993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold SpiRecord( 30093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold int resourceId, 3018dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold IBinder binder, 30293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold int direction, 30393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold String localAddress, 30493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold String remoteAddress, 3058dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold int spi) { 3068dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold super(resourceId, binder); 30793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold mDirection = direction; 30893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold mLocalAddress = localAddress; 30993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold mRemoteAddress = remoteAddress; 31093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold mSpi = spi; 31193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 31293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 3138dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold /** always guarded by IpSecService#this */ 3148dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold @Override 31593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold protected void releaseResources() { 3168dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (mOwnedByTransform) { 3178dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold Log.d(TAG, "Cannot release Spi " + mSpi + ": Currently locked by a Transform"); 3188dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // Because SPIs are "handed off" to transform, objects, they should never be 3198dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // freed from the SpiRecord once used in a transform. (They refer to the same SA, 3208dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // thus ownership and responsibility for freeing these resources passes to the 3218dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // Transform object). Thus, we should let the user free them without penalty once 3228dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // they are applied in a Transform object. 3238dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return; 3248dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 3258dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 32693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold try { 32793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold getNetdInstance() 32893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold .ipSecDeleteSecurityAssociation( 32993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold mResourceId, mDirection, mLocalAddress, mRemoteAddress, mSpi); 33093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } catch (ServiceSpecificException e) { 33193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold // FIXME: get the error code and throw is at an IOException from Errno Exception 33293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } catch (RemoteException e) { 33393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId); 33493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 33593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 33693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; 3378dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 3388dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 3398dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public int getSpi() { 3408dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return mSpi; 3418dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 3428dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 3438dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public void setOwnedByTransform() { 3448dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (mOwnedByTransform) { 3458dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // Programming error 346d6d8e452c15cd7f7020891601e41a9561dedc468Andreas Gampe throw new IllegalStateException("Cannot own an SPI twice!"); 3478dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 3488dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 3498dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mOwnedByTransform = true; 35093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 35193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 35293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 3538dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private final class UdpSocketRecord extends ManagedResource { 3548dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private FileDescriptor mSocket; 3558dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private final int mPort; 3568dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 3578dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold UdpSocketRecord(int resourceId, IBinder binder, FileDescriptor socket, int port) { 3588dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold super(resourceId, binder); 3598dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mSocket = socket; 3608dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mPort = port; 3618dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 3628dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 3638dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold /** always guarded by IpSecService#this */ 3648dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold @Override 3658dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold protected void releaseResources() { 3668dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold Log.d(TAG, "Closing port " + mPort); 3678dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold IoUtils.closeQuietly(mSocket); 3688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mSocket = null; 3698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 3708dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 3718dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public int getPort() { 3728dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return mPort; 3738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 37493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 3758dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public FileDescriptor getSocket() { 3768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return mSocket; 3778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 3788dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 37993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 3801afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold /** 3811afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * Constructs a new IpSecService instance 3821afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * 3831afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * @param context Binder context for this service 3841afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold */ 3851afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold private IpSecService(Context context) { 3861afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold mContext = context; 3871afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 3881afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold 3891afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold static IpSecService create(Context context) throws InterruptedException { 3901afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold final IpSecService service = new IpSecService(context); 3911afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold service.connectNativeNetdService(); 3921afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold return service; 3931afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 3941afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold 3951afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold public void systemReady() { 3961afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold if (isNetdAlive()) { 3971afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold Slog.d(TAG, "IpSecService is ready"); 3981afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } else { 3991afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold Slog.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!"); 4001afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 4011afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 4021afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold 4031afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold private void connectNativeNetdService() { 4041afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold // Avoid blocking the system server to do this 4051afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold Thread t = 4061afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold new Thread( 4071afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold new Runnable() { 4081afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold @Override 4091afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold public void run() { 4108dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold synchronized (IpSecService.this) { 4111afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold NetdService.get(NETD_FETCH_TIMEOUT); 4121afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 4131afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 4141afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold }); 4151afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold t.run(); 4161afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 4171afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold 41893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold INetd getNetdInstance() throws RemoteException { 4191afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold final INetd netd = NetdService.getInstance(); 4201afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold if (netd == null) { 42193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold throw new RemoteException("Failed to Get Netd Instance"); 4221afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 4231afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold return netd; 4241afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 4251afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold 4268dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold synchronized boolean isNetdAlive() { 4278dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold try { 4288dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold final INetd netd = getNetdInstance(); 4298dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (netd == null) { 4301afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold return false; 4311afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 4328dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return netd.isAlive(); 4338dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } catch (RemoteException re) { 4348dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return false; 4351afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 4361afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 4371afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold 4381afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold @Override 43993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold /** Get a new SPI and maintain the reservation in the system server */ 4408dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public synchronized IpSecSpiResponse reserveSecurityParameterIndex( 44193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold int direction, String remoteAddress, int requestedSpi, IBinder binder) 44293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold throws RemoteException { 44393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold int resourceId = mNextResourceId.getAndIncrement(); 44493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 44593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; 44693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold String localAddress = ""; 44793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold try { 44893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold spi = 44993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold getNetdInstance() 45093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold .ipSecAllocateSpi( 45193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold resourceId, 45293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold direction, 45393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold localAddress, 45493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold remoteAddress, 45593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold requestedSpi); 45693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold Log.d(TAG, "Allocated SPI " + spi); 4578dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mSpiRecords.put( 4588dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold resourceId, 4598dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold new SpiRecord(resourceId, binder, direction, localAddress, remoteAddress, spi)); 46093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } catch (ServiceSpecificException e) { 46193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold // TODO: Add appropriate checks when other ServiceSpecificException types are supported 4628dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return new IpSecSpiResponse( 4638dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold IpSecManager.Status.SPI_UNAVAILABLE, IpSecManager.INVALID_RESOURCE_ID, spi); 46493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } catch (RemoteException e) { 46593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold throw e.rethrowFromSystemServer(); 46693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 4678dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, spi); 4688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 4698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 4708dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold /* This method should only be called from Binder threads. Do not call this from 4718dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * within the system server as it will crash the system on failure. 4728dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold */ 4738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private synchronized <T extends ManagedResource> void releaseManagedResource( 4748dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold ManagedResourceArray<T> resArray, int resourceId, String typeName) 4758dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold throws RemoteException { 4768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // We want to non-destructively get so that we can check credentials before removing 4778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // this from the records. 4788dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold T record = resArray.get(resourceId); 4798dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 4808dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (record == null) { 4818dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold throw new IllegalArgumentException( 4828dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold typeName + " " + resourceId + " is not available to be deleted"); 4838dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 4848dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 4858dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold record.release(); 4868dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold resArray.remove(resourceId); 48793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 48893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 48993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold /** Release a previously allocated SPI that has been registered with the system server */ 49093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold @Override 4918dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public void releaseSecurityParameterIndex(int resourceId) throws RemoteException { 4928dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold releaseManagedResource(mSpiRecords, resourceId, "SecurityParameterIndex"); 4938dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 4948dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 4958dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold /** 4968dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * This function finds and forcibly binds to a random system port, ensuring that the port cannot 4978dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * be unbound. 4988dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * 4998dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * <p>A socket cannot be un-bound from a port if it was bound to that port by number. To select 5008dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * a random open port and then bind by number, this function creates a temp socket, binds to a 5018dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * random port (specifying 0), gets that port number, and then uses is to bind the user's UDP 5028dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * Encapsulation Socket forcibly, so that it cannot be un-bound by the user with the returned 5038dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * FileHandle. 5048dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * 5058dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * <p>The loop in this function handles the inherent race window between un-binding to a port 5068dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * and re-binding, during which the system could *technically* hand that port out to someone 5078dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold * else. 5088dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold */ 5098dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold private void bindToRandomPort(FileDescriptor sockFd) throws IOException { 5108dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold for (int i = MAX_PORT_BIND_ATTEMPTS; i > 0; i--) { 5118dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold try { 5128dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold FileDescriptor probeSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 5138dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold Os.bind(probeSocket, INADDR_ANY, 0); 5148dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold int port = ((InetSocketAddress) Os.getsockname(probeSocket)).getPort(); 5158dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold Os.close(probeSocket); 5168dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold Log.v(TAG, "Binding to port " + port); 5178dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold Os.bind(sockFd, INADDR_ANY, port); 5188dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return; 5198dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } catch (ErrnoException e) { 5208dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // Someone miraculously claimed the port just after we closed probeSocket. 5218dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (e.errno == OsConstants.EADDRINUSE) { 5228dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold continue; 5238dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 5248dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold throw e.rethrowAsIOException(); 5258dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 5268dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 5278dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold throw new IOException("Failed " + MAX_PORT_BIND_ATTEMPTS + " attempts to bind to a port"); 5288dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 52993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 53093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold /** 53193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * Open a socket via the system server and bind it to the specified port (random if port=0). 53293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * This will return a PFD to the user that represent a bound UDP socket. The system server will 53393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * cache the socket and a record of its owner so that it can and must be freed when no longer 53493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * needed. 53593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold */ 53693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold @Override 5378dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public synchronized IpSecUdpEncapResponse openUdpEncapsulationSocket(int port, IBinder binder) 5388dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold throws RemoteException { 5398dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (port != 0 && (port < FREE_PORT_MIN || port > PORT_MAX)) { 5408dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold throw new IllegalArgumentException( 5418dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold "Specified port number must be a valid non-reserved UDP port"); 5428dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 5438dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold int resourceId = mNextResourceId.getAndIncrement(); 5448dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold FileDescriptor sockFd = null; 5458dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold try { 5468dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 5478dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 5488dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (port != 0) { 5498dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold Log.v(TAG, "Binding to port " + port); 5508dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold Os.bind(sockFd, INADDR_ANY, port); 5518dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } else { 5528dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold bindToRandomPort(sockFd); 5538dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 5548dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // This code is common to both the unspecified and specified port cases 5558dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold Os.setsockoptInt( 5568dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold sockFd, 5578dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold OsConstants.IPPROTO_UDP, 5588dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold OsConstants.UDP_ENCAP, 5598dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold OsConstants.UDP_ENCAP_ESPINUDP); 5608dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 5618dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mUdpSocketRecords.put( 5628dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold resourceId, new UdpSocketRecord(resourceId, binder, sockFd, port)); 5638dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return new IpSecUdpEncapResponse(IpSecManager.Status.OK, resourceId, port, sockFd); 5648dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } catch (IOException | ErrnoException e) { 5658dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold IoUtils.closeQuietly(sockFd); 5668dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 5678dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // If we make it to here, then something has gone wrong and we couldn't open a socket. 5688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // The only reasonable condition that would cause that is resource unavailable. 5698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return new IpSecUdpEncapResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); 57093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 57193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 57293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold /** close a socket that has been been allocated by and registered with the system server */ 57393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold @Override 5748dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public void closeUdpEncapsulationSocket(int resourceId) throws RemoteException { 5758dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 5768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold releaseManagedResource(mUdpSocketRecords, resourceId, "UdpEncapsulationSocket"); 5778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 57893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 57993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold /** 58093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * Create a transport mode transform, which represent two security associations (one in each 58193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * direction) in the kernel. The transform will be cached by the system server and must be freed 58293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * when no longer needed. It is possible to free one, deleting the SA from underneath sockets 58393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * that are using it, which will result in all of those sockets becoming unable to send or 58493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * receive data. 58593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold */ 58693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold @Override 5878dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public synchronized IpSecTransformResponse createTransportModeTransform( 5888dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold IpSecConfig c, IBinder binder) throws RemoteException { 58993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold int resourceId = mNextResourceId.getAndIncrement(); 5908dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold SpiRecord[] spis = new SpiRecord[DIRECTIONS.length]; 5918dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // TODO: Basic input validation here since it's coming over the Binder 5928dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold int encapType, encapLocalPort = 0, encapRemotePort = 0; 5938dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold UdpSocketRecord socketRecord = null; 5948dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold encapType = c.getEncapType(); 5958dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (encapType != IpSecTransform.ENCAP_NONE) { 5968dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold socketRecord = mUdpSocketRecords.get(c.getEncapLocalResourceId()); 5978dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold encapLocalPort = socketRecord.getPort(); 5988dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold encapRemotePort = c.getEncapRemotePort(); 5998dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 6008dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 60193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold for (int direction : DIRECTIONS) { 60293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold IpSecAlgorithm auth = c.getAuthentication(direction); 60393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold IpSecAlgorithm crypt = c.getEncryption(direction); 6048dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 6058dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold spis[direction] = mSpiRecords.get(c.getSpiResourceId(direction)); 6068dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold int spi = spis[direction].getSpi(); 60793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold try { 60893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold int result = 60993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold getNetdInstance() 61093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold .ipSecAddSecurityAssociation( 61193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold resourceId, 61293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold c.getMode(), 61393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold direction, 61493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold (c.getLocalAddress() != null) 61593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold ? c.getLocalAddress().getHostAddress() 61693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold : "", 61793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold (c.getRemoteAddress() != null) 61893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold ? c.getRemoteAddress().getHostAddress() 61993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold : "", 62093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold (c.getNetwork() != null) 62193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold ? c.getNetwork().getNetworkHandle() 62293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold : 0, 6238dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold spi, 62493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold (auth != null) ? auth.getName() : "", 62593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold (auth != null) ? auth.getKey() : null, 62693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold (auth != null) ? auth.getTruncationLengthBits() : 0, 62793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold (crypt != null) ? crypt.getName() : "", 62893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold (crypt != null) ? crypt.getKey() : null, 62993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold (crypt != null) ? crypt.getTruncationLengthBits() : 0, 6308dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold encapType, 6318dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold encapLocalPort, 6328dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold encapRemotePort); 6338dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (result != spi) { 63493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold // TODO: cleanup the first SA if creation of second SA fails 6358dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return new IpSecTransformResponse( 6368dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold IpSecManager.Status.SPI_UNAVAILABLE, INVALID_RESOURCE_ID); 63793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 63893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } catch (ServiceSpecificException e) { 63993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold // FIXME: get the error code and throw is at an IOException from Errno Exception 64093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 64193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 6428dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // Both SAs were created successfully, time to construct a record and lock it away 6438dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold mTransformRecords.put( 6448dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold resourceId, new TransformRecord(resourceId, binder, c, spis, socketRecord)); 6458dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold return new IpSecTransformResponse(IpSecManager.Status.OK, resourceId); 64693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 64793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 64893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold /** 64993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * Delete a transport mode transform that was previously allocated by + registered with the 65093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * system server. If this is called on an inactive (or non-existent) transform, it will not 65193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * return an error. It's safe to de-allocate transforms that may have already been deleted for 65293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * other reasons. 65393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold */ 65493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold @Override 65593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold public void deleteTransportModeTransform(int resourceId) throws RemoteException { 6568dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold releaseManagedResource(mTransformRecords, resourceId, "IpSecTransform"); 65793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 65893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 65993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold /** 66093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * Apply an active transport mode transform to a socket, which will apply the IPsec security 66193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * association as a correspondent policy to the provided socket 66293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold */ 66393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold @Override 6648dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold public synchronized void applyTransportModeTransform( 6658dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold ParcelFileDescriptor socket, int resourceId) throws RemoteException { 6668dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // Synchronize liberally here because we are using ManagedResources in this block 6678dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold TransformRecord info; 6688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // FIXME: this code should be factored out into a security check + getter 6698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold info = mTransformRecords.get(resourceId); 6708dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 6718dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (info == null) { 6728dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold throw new IllegalArgumentException("Transform " + resourceId + " is not active"); 6738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 67493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 6758dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // TODO: make this a function. 6768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold if (info.pid != getCallingPid() || info.uid != getCallingUid()) { 6778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold throw new SecurityException("Only the owner of an IpSec Transform may apply it!"); 6788dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } 67993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 6808dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold IpSecConfig c = info.getConfig(); 6818dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold try { 6828dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold for (int direction : DIRECTIONS) { 6838dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold getNetdInstance() 6848dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold .ipSecApplyTransportModeTransform( 6858dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold socket.getFileDescriptor(), 6868dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold resourceId, 6878dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold direction, 6888dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold (c.getLocalAddress() != null) 6898dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold ? c.getLocalAddress().getHostAddress() 6908dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold : "", 6918dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold (c.getRemoteAddress() != null) 6928dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold ? c.getRemoteAddress().getHostAddress() 6938dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold : "", 6948dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold info.getSpiRecord(direction).getSpi()); 69593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 6968dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold } catch (ServiceSpecificException e) { 6978dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // FIXME: get the error code and throw is at an IOException from Errno Exception 69893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 69993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 7008dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold 70193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold /** 70293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * Remove a transport mode transform from a socket, applying the default (empty) policy. This 70393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * will ensure that NO IPsec policy is applied to the socket (would be the equivalent of 70493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * applying a policy that performs no IPsec). Today the resourceId parameter is passed but not 70593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold * used: reserved for future improved input validation. 70693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold */ 70793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold @Override 70893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold public void removeTransportModeTransform(ParcelFileDescriptor socket, int resourceId) 70993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold throws RemoteException { 71093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold try { 71193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold getNetdInstance().ipSecRemoveTransportModeTransform(socket.getFileDescriptor()); 71293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } catch (ServiceSpecificException e) { 71393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold // FIXME: get the error code and throw is at an IOException from Errno Exception 71493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 71593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold } 71693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold 71793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold @Override 7181afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 7191afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold mContext.enforceCallingOrSelfPermission(DUMP, TAG); 7208dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold // TODO: Add dump code to print out a log of all the resources being tracked 7211afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold pw.println("IpSecService Log:"); 7221afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead")); 7231afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold pw.println(); 7241afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold } 7251afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold} 726