1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.net.ipsec.ike; 18 19 import static android.net.ipsec.ike.IkeManager.getIkeLog; 20 21 import android.net.IpSecManager; 22 import android.net.IpSecManager.ResourceUnavailableException; 23 import android.net.IpSecManager.UdpEncapsulationSocket; 24 import android.os.Handler; 25 import android.os.Looper; 26 import android.system.ErrnoException; 27 28 import com.android.internal.annotations.VisibleForTesting; 29 30 import java.io.FileDescriptor; 31 import java.io.IOException; 32 import java.net.InetAddress; 33 import java.util.Arrays; 34 import java.util.HashMap; 35 import java.util.Map; 36 37 /** 38 * IkeUdpEncapSocket uses an {@link UdpEncapsulationSocket} to send and receive IKE packets. 39 * 40 * <p>Caller MUST provide one IkeSocketConfig when trying to get an instance of IkeUdpEncapSocket. 41 * Each IkeSocketConfig can only be bound by one IkeUdpEncapSocket instance. When caller requests 42 * for IkeUdpEncapSocket with an already bound IkeSocketConfig, an existing instance will be 43 * returned. 44 */ 45 public final class IkeUdpEncapSocket extends IkeSocket { 46 private static final String TAG = "IkeUdpEncapSocket"; 47 48 // Map from IkeSocketConfig to IkeSocket instances. 49 private static Map<IkeSocketConfig, IkeUdpEncapSocket> sConfigToSocketMap = new HashMap<>(); 50 51 private static IPacketReceiver sPacketReceiver = 52 new IkeUdpEncapPortPacketHandler.PacketReceiver(); 53 54 // UdpEncapsulationSocket for sending and receving IKE packet. 55 private final UdpEncapsulationSocket mUdpEncapSocket; 56 57 private final IkeUdpEncapPortPacketHandler mUdpEncapPortPacketHandler; 58 IkeUdpEncapSocket( UdpEncapsulationSocket udpEncapSocket, IkeSocketConfig sockConfig, Handler handler)59 private IkeUdpEncapSocket( 60 UdpEncapsulationSocket udpEncapSocket, IkeSocketConfig sockConfig, Handler handler) { 61 super(sockConfig, handler); 62 mUdpEncapSocket = udpEncapSocket; 63 64 mUdpEncapPortPacketHandler = new IkeUdpEncapPortPacketHandler(getFd()); 65 } 66 67 /** 68 * Get an IkeUdpEncapSocket instance. 69 * 70 * <p>Return the existing IkeUdpEncapSocket instance if it has been created for the input 71 * IkeSocketConfig. Otherwise, create and return a new IkeUdpEncapSocket instance. 72 * 73 * @param sockConfig the socket configuration 74 * @param ipsecManager for creating {@link UdpEncapsulationSocket} 75 * @param callback the callback for signalling IkeSocket events 76 * @return an IkeUdpEncapSocket instance 77 */ getIkeUdpEncapSocket( IkeSocketConfig sockConfig, IpSecManager ipsecManager, IkeSocket.Callback callback, Looper looper)78 public static IkeUdpEncapSocket getIkeUdpEncapSocket( 79 IkeSocketConfig sockConfig, 80 IpSecManager ipsecManager, 81 IkeSocket.Callback callback, 82 Looper looper) 83 throws ErrnoException, IOException, ResourceUnavailableException { 84 IkeUdpEncapSocket ikeSocket = sConfigToSocketMap.get(sockConfig); 85 if (ikeSocket == null) { 86 UdpEncapsulationSocket udpEncapSocket = ipsecManager.openUdpEncapsulationSocket(); 87 FileDescriptor fd = udpEncapSocket.getFileDescriptor(); 88 applySocketConfig(sockConfig, fd, false /* isIpv6 */); 89 90 ikeSocket = new IkeUdpEncapSocket(udpEncapSocket, sockConfig, new Handler(looper)); 91 92 // Create and register FileDescriptor for receiving IKE packet on current thread. 93 ikeSocket.start(); 94 95 sConfigToSocketMap.put(sockConfig, ikeSocket); 96 } 97 ikeSocket.mRegisteredCallbacks.add(callback); 98 return ikeSocket; 99 } 100 101 /** 102 * Returns the {@link UdpEncapsulationSocket} 103 * 104 * @return the {@link UdpEncapsulationSocket} for sending and receiving IKE packets. 105 */ getUdpEncapsulationSocket()106 public UdpEncapsulationSocket getUdpEncapsulationSocket() { 107 return mUdpEncapSocket; 108 } 109 110 /** Get FileDescriptor for use with the packet reader polling loop */ 111 @Override getFd()112 protected FileDescriptor getFd() { 113 return mUdpEncapSocket.getFileDescriptor(); // Returns cached FD 114 } 115 116 /** Package private */ 117 @VisibleForTesting setPacketReceiver(IkeSocket.IPacketReceiver receiver)118 static void setPacketReceiver(IkeSocket.IPacketReceiver receiver) { 119 sPacketReceiver = receiver; 120 } 121 122 /** 123 * Handle received IKE packet. Invoked when there is a read event. Any desired copies of 124 * |recvbuf| should be made in here, as the underlying byte array is reused across all reads. 125 */ 126 @Override handlePacket(byte[] recvbuf, int length)127 protected void handlePacket(byte[] recvbuf, int length) { 128 sPacketReceiver.handlePacket(Arrays.copyOfRange(recvbuf, 0, length), mSpiToCallback); 129 } 130 131 @Override sendIkePacket(byte[] ikePacket, InetAddress serverAddress)132 public void sendIkePacket(byte[] ikePacket, InetAddress serverAddress) { 133 mUdpEncapPortPacketHandler.sendIkePacket(ikePacket, serverAddress); 134 } 135 136 @Override getIkeServerPort()137 public int getIkeServerPort() { 138 return SERVER_PORT_UDP_ENCAPSULATED; 139 } 140 141 /** Implement {@link AutoCloseable#close()} */ 142 @Override close()143 public void close() { 144 sConfigToSocketMap.remove(getIkeSocketConfig()); 145 146 try { 147 mUdpEncapSocket.close(); 148 } catch (IOException e) { 149 getIkeLog() 150 .e( 151 TAG, 152 "Failed to close UDP Encapsulation Socket with Port= " 153 + mUdpEncapSocket.getPort()); 154 } 155 156 // PacketReader unregisters file descriptor on thread with which the Handler constructor 157 // argument is associated. 158 super.close(); 159 } 160 } 161