blob: b6130ad53f255171b905d21683d6d47617090d3e [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.net.ipsec.ike;
import static android.net.ipsec.ike.IkeManager.getIkeLog;
import android.net.Network;
import android.os.Handler;
import android.system.ErrnoException;
import android.system.Os;
import android.util.LongSparseArray;
import com.android.internal.annotations.VisibleForTesting;
import java.io.FileDescriptor;
import java.io.IOException;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.Arrays;
/** IkeUdpSocket is an abstract superclass for all non-encapsulating IKE UDP sockets. */
public abstract class IkeUdpSocket extends IkeSocket {
private static final String TAG = IkeUdpSocket.class.getSimpleName();
protected static IPacketReceiver sPacketReceiver = new PacketReceiver();
// FileDescriptor for sending and receving IKE packet.
protected final FileDescriptor mSocket;
protected IkeUdpSocket(FileDescriptor socket, Network network, Handler handler) {
super(network, handler);
mSocket = socket;
}
/** Get FileDescriptor for use with the packet reader polling loop */
@Override
protected FileDescriptor getFd() {
return mSocket;
}
/** Package private */
@VisibleForTesting
static final class PacketReceiver implements IkeSocket.IPacketReceiver {
public void handlePacket(
byte[] recvbuf, LongSparseArray<IkeSessionStateMachine> spiToIkeSession) {
ByteBuffer byteBuffer = ByteBuffer.wrap(recvbuf);
// Re-direct IKE packet to IkeSessionStateMachine according to the locally generated
// IKE SPI.
byte[] ikePacketBytes = new byte[byteBuffer.remaining()];
byteBuffer.get(ikePacketBytes);
parseAndDemuxIkePacket(ikePacketBytes, spiToIkeSession, TAG);
}
}
/** Package private */
@VisibleForTesting
static void setPacketReceiver(IkeSocket.IPacketReceiver receiver) {
sPacketReceiver = receiver;
}
/**
* Handle received IKE packet. Invoked when there is a read event. Any desired copies of
* |recvbuf| should be made in here, as the underlying byte array is reused across all reads.
*/
@Override
protected void handlePacket(byte[] recvbuf, int length) {
sPacketReceiver.handlePacket(Arrays.copyOfRange(recvbuf, 0, length), mSpiToIkeSession);
}
/**
* Send encoded IKE packet to destination address
*
* @param ikePacket encoded IKE packet
* @param serverAddress IP address of remote server
*/
@Override
public void sendIkePacket(byte[] ikePacket, InetAddress serverAddress) {
getIkeLog()
.d(
this.getClass().getSimpleName(),
"Sending packet to "
+ serverAddress.getHostAddress()
+ "( "
+ ikePacket.length
+ " bytes)");
try {
ByteBuffer buffer = ByteBuffer.wrap(ikePacket);
// Use unconnected UDP socket because one {@IkeUdpSocket} may be shared by
// multiple IKE sessions that send messages to different destinations.
Os.sendto(mSocket, buffer, 0, serverAddress, getIkeServerPort());
} catch (ErrnoException | IOException e) {
getIkeLog()
.i(
this.getClass().getSimpleName(),
"Failed to send packet on network " + getNetwork(),
e);
}
}
@Override
public int getIkeServerPort() {
return SERVER_PORT_NON_UDP_ENCAPSULATED;
}
/** Implement {@link AutoCloseable#close()} */
@Override
public void close() {
try {
Os.close(mSocket);
} catch (ErrnoException e) {
getIkeLog()
.e(
this.getClass().getSimpleName(),
"Failed to close UDP Encapsulation Socket for Network " + getNetwork());
}
// PacketReader unregisters file descriptor from listener on thread with which the Handler
// constructor argument is associated.
super.close();
}
}