diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/android/net/ip/IpNeighborMonitor.java | 241 | ||||
-rw-r--r-- | src/android/net/util/FdEventsReader.java | 259 | ||||
-rw-r--r-- | src/android/net/util/PacketReader.java | 59 |
3 files changed, 0 insertions, 559 deletions
diff --git a/src/android/net/ip/IpNeighborMonitor.java b/src/android/net/ip/IpNeighborMonitor.java deleted file mode 100644 index 803f2e6..0000000 --- a/src/android/net/ip/IpNeighborMonitor.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright (C) 2017 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 android.net.ip; - -import static android.net.netlink.NetlinkConstants.RTM_DELNEIGH; -import static android.net.netlink.NetlinkConstants.hexify; -import static android.net.netlink.NetlinkConstants.stringForNlMsgType; -import static android.net.util.SocketUtils.makeNetlinkSocketAddress; -import static android.system.OsConstants.AF_NETLINK; -import static android.system.OsConstants.NETLINK_ROUTE; -import static android.system.OsConstants.SOCK_DGRAM; -import static android.system.OsConstants.SOCK_NONBLOCK; - -import android.net.MacAddress; -import android.net.netlink.NetlinkErrorMessage; -import android.net.netlink.NetlinkMessage; -import android.net.netlink.NetlinkSocket; -import android.net.netlink.RtNetlinkNeighborMessage; -import android.net.netlink.StructNdMsg; -import android.net.util.NetworkStackUtils; -import android.net.util.PacketReader; -import android.net.util.SharedLog; -import android.os.Handler; -import android.os.SystemClock; -import android.system.ErrnoException; -import android.system.Os; -import android.system.OsConstants; -import android.util.Log; - -import java.io.FileDescriptor; -import java.net.InetAddress; -import java.net.SocketAddress; -import java.net.SocketException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.StringJoiner; - - -/** - * IpNeighborMonitor. - * - * Monitors the kernel rtnetlink neighbor notifications and presents to callers - * NeighborEvents describing each event. Callers can provide a consumer instance - * to both filter (e.g. by interface index and IP address) and handle the - * generated NeighborEvents. - * - * @hide - */ -public class IpNeighborMonitor extends PacketReader { - private static final String TAG = IpNeighborMonitor.class.getSimpleName(); - private static final boolean DBG = false; - private static final boolean VDBG = false; - - /** - * Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND) - * for the given IP address on the specified interface index. - * - * @return 0 if the request was successfully passed to the kernel; otherwise return - * a non-zero error code. - */ - public static int startKernelNeighborProbe(int ifIndex, InetAddress ip) { - final String msgSnippet = "probing ip=" + ip.getHostAddress() + "%" + ifIndex; - if (DBG) { Log.d(TAG, msgSnippet); } - - final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage( - 1, ip, StructNdMsg.NUD_PROBE, ifIndex, null); - - try { - NetlinkSocket.sendOneShotKernelMessage(NETLINK_ROUTE, msg); - } catch (ErrnoException e) { - Log.e(TAG, "Error " + msgSnippet + ": " + e); - return -e.errno; - } - - return 0; - } - - public static class NeighborEvent { - final long elapsedMs; - final short msgType; - final int ifindex; - final InetAddress ip; - final short nudState; - final MacAddress macAddr; - - public NeighborEvent(long elapsedMs, short msgType, int ifindex, InetAddress ip, - short nudState, MacAddress macAddr) { - this.elapsedMs = elapsedMs; - this.msgType = msgType; - this.ifindex = ifindex; - this.ip = ip; - this.nudState = nudState; - this.macAddr = macAddr; - } - - boolean isConnected() { - return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateConnected(nudState); - } - - boolean isValid() { - return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateValid(nudState); - } - - @Override - public String toString() { - final StringJoiner j = new StringJoiner(",", "NeighborEvent{", "}"); - return j.add("@" + elapsedMs) - .add(stringForNlMsgType(msgType)) - .add("if=" + ifindex) - .add(ip.getHostAddress()) - .add(StructNdMsg.stringForNudState(nudState)) - .add("[" + macAddr + "]") - .toString(); - } - } - - public interface NeighborEventConsumer { - // Every neighbor event received on the netlink socket is passed in - // here. Subclasses should filter for events of interest. - public void accept(NeighborEvent event); - } - - private final SharedLog mLog; - private final NeighborEventConsumer mConsumer; - - public IpNeighborMonitor(Handler h, SharedLog log, NeighborEventConsumer cb) { - super(h, NetlinkSocket.DEFAULT_RECV_BUFSIZE); - mLog = log.forSubComponent(TAG); - mConsumer = (cb != null) ? cb : (event) -> { /* discard */ }; - } - - @Override - protected FileDescriptor createFd() { - FileDescriptor fd = null; - - try { - fd = Os.socket(AF_NETLINK, SOCK_DGRAM | SOCK_NONBLOCK, NETLINK_ROUTE); - Os.bind(fd, makeNetlinkSocketAddress(0, OsConstants.RTMGRP_NEIGH)); - NetlinkSocket.connectToKernel(fd); - - if (VDBG) { - final SocketAddress nlAddr = Os.getsockname(fd); - Log.d(TAG, "bound to sockaddr_nl{" + nlAddr.toString() + "}"); - } - } catch (ErrnoException|SocketException e) { - logError("Failed to create rtnetlink socket", e); - NetworkStackUtils.closeSocketQuietly(fd); - return null; - } - - return fd; - } - - @Override - protected void handlePacket(byte[] recvbuf, int length) { - final long whenMs = SystemClock.elapsedRealtime(); - - final ByteBuffer byteBuffer = ByteBuffer.wrap(recvbuf, 0, length); - byteBuffer.order(ByteOrder.nativeOrder()); - - parseNetlinkMessageBuffer(byteBuffer, whenMs); - } - - private void parseNetlinkMessageBuffer(ByteBuffer byteBuffer, long whenMs) { - while (byteBuffer.remaining() > 0) { - final int position = byteBuffer.position(); - final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer); - if (nlMsg == null || nlMsg.getHeader() == null) { - byteBuffer.position(position); - mLog.e("unparsable netlink msg: " + hexify(byteBuffer)); - break; - } - - if (nlMsg instanceof NetlinkErrorMessage) { - mLog.e("netlink error: " + nlMsg); - continue; - } else if (!(nlMsg instanceof RtNetlinkNeighborMessage)) { - mLog.i("non-rtnetlink neighbor msg: " + nlMsg); - continue; - } - - evaluateRtNetlinkNeighborMessage((RtNetlinkNeighborMessage) nlMsg, whenMs); - } - } - - private void evaluateRtNetlinkNeighborMessage( - RtNetlinkNeighborMessage neighMsg, long whenMs) { - final short msgType = neighMsg.getHeader().nlmsg_type; - final StructNdMsg ndMsg = neighMsg.getNdHeader(); - if (ndMsg == null) { - mLog.e("RtNetlinkNeighborMessage without ND message header!"); - return; - } - - final int ifindex = ndMsg.ndm_ifindex; - final InetAddress destination = neighMsg.getDestination(); - final short nudState = - (msgType == RTM_DELNEIGH) - ? StructNdMsg.NUD_NONE - : ndMsg.ndm_state; - - final NeighborEvent event = new NeighborEvent( - whenMs, msgType, ifindex, destination, nudState, - getMacAddress(neighMsg.getLinkLayerAddress())); - - if (VDBG) { - Log.d(TAG, neighMsg.toString()); - } - if (DBG) { - Log.d(TAG, event.toString()); - } - - mConsumer.accept(event); - } - - private static MacAddress getMacAddress(byte[] linkLayerAddress) { - if (linkLayerAddress != null) { - try { - return MacAddress.fromBytes(linkLayerAddress); - } catch (IllegalArgumentException e) { - Log.e(TAG, "Failed to parse link-layer address: " + hexify(linkLayerAddress)); - } - } - - return null; - } -} diff --git a/src/android/net/util/FdEventsReader.java b/src/android/net/util/FdEventsReader.java deleted file mode 100644 index 5a1154f..0000000 --- a/src/android/net/util/FdEventsReader.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (C) 2016 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 android.net.util; - -import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR; -import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; - -import android.os.Handler; -import android.os.Looper; -import android.os.MessageQueue; -import android.system.ErrnoException; -import android.system.OsConstants; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.io.FileDescriptor; -import java.io.IOException; - - -/** - * This class encapsulates the mechanics of registering a file descriptor - * with a thread's Looper and handling read events (and errors). - * - * Subclasses MUST implement createFd() and SHOULD override handlePacket(). They MAY override - * onStop() and onStart(). - * - * Subclasses can expect a call life-cycle like the following: - * - * [1] when a client calls start(), createFd() is called, followed by the onStart() hook if all - * goes well. Implementations may override onStart() for additional initialization. - * - * [2] yield, waiting for read event or error notification: - * - * [a] readPacket() && handlePacket() - * - * [b] if (no error): - * goto 2 - * else: - * goto 3 - * - * [3] when a client calls stop(), the onStop() hook is called (unless already stopped or never - * started). Implementations may override onStop() for additional cleanup. - * - * The packet receive buffer is recycled on every read call, so subclasses - * should make any copies they would like inside their handlePacket() - * implementation. - * - * All public methods MUST only be called from the same thread with which - * the Handler constructor argument is associated. - * - * @param <BufferType> the type of the buffer used to read data. - */ -public abstract class FdEventsReader<BufferType> { - private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR; - private static final int UNREGISTER_THIS_FD = 0; - - @NonNull - private final Handler mHandler; - @NonNull - private final MessageQueue mQueue; - @NonNull - private final BufferType mBuffer; - @Nullable - private FileDescriptor mFd; - private long mPacketsReceived; - - protected static void closeFd(FileDescriptor fd) { - try { - SocketUtils.closeSocket(fd); - } catch (IOException ignored) { - } - } - - protected FdEventsReader(@NonNull Handler h, @NonNull BufferType buffer) { - mHandler = h; - mQueue = mHandler.getLooper().getQueue(); - mBuffer = buffer; - } - - /** Start this FdEventsReader. */ - public boolean start() { - if (!onCorrectThread()) { - throw new IllegalStateException("start() called from off-thread"); - } - - return createAndRegisterFd(); - } - - /** Stop this FdEventsReader and destroy the file descriptor. */ - public void stop() { - if (!onCorrectThread()) { - throw new IllegalStateException("stop() called from off-thread"); - } - - unregisterAndDestroyFd(); - } - - @NonNull - public Handler getHandler() { - return mHandler; - } - - protected abstract int recvBufSize(@NonNull BufferType buffer); - - /** Returns the size of the receive buffer. */ - public int recvBufSize() { - return recvBufSize(mBuffer); - } - - /** - * Get the number of successful calls to {@link #readPacket(FileDescriptor, Object)}. - * - * <p>A call was successful if {@link #readPacket(FileDescriptor, Object)} returned a value > 0. - */ - public final long numPacketsReceived() { - return mPacketsReceived; - } - - /** - * Subclasses MUST create the listening socket here, including setting all desired socket - * options, interface or address/port binding, etc. The socket MUST be created nonblocking. - */ - @Nullable - protected abstract FileDescriptor createFd(); - - /** - * Implementations MUST return the bytes read or throw an Exception. - * - * <p>The caller may throw a {@link ErrnoException} with {@link OsConstants#EAGAIN} or - * {@link OsConstants#EINTR}, in which case {@link FdEventsReader} will ignore the buffer - * contents and respectively wait for further input or retry the read immediately. For all other - * exceptions, the {@link FdEventsReader} will be stopped with no more interactions with this - * method. - */ - protected abstract int readPacket(@NonNull FileDescriptor fd, @NonNull BufferType buffer) - throws Exception; - - /** - * Called by the main loop for every packet. Any desired copies of - * |recvbuf| should be made in here, as the underlying byte array is - * reused across all reads. - */ - protected void handlePacket(@NonNull BufferType recvbuf, int length) {} - - /** - * Called by the main loop to log errors. In some cases |e| may be null. - */ - protected void logError(@NonNull String msg, @Nullable Exception e) {} - - /** - * Called by start(), if successful, just prior to returning. - */ - protected void onStart() {} - - /** - * Called by stop() just prior to returning. - */ - protected void onStop() {} - - private boolean createAndRegisterFd() { - if (mFd != null) return true; - - try { - mFd = createFd(); - } catch (Exception e) { - logError("Failed to create socket: ", e); - closeFd(mFd); - mFd = null; - } - - if (mFd == null) return false; - - mQueue.addOnFileDescriptorEventListener( - mFd, - FD_EVENTS, - (fd, events) -> { - // Always call handleInput() so read/recvfrom are given - // a proper chance to encounter a meaningful errno and - // perhaps log a useful error message. - if (!isRunning() || !handleInput()) { - unregisterAndDestroyFd(); - return UNREGISTER_THIS_FD; - } - return FD_EVENTS; - }); - onStart(); - return true; - } - - private boolean isRunning() { - return (mFd != null) && mFd.valid(); - } - - // Keep trying to read until we get EAGAIN/EWOULDBLOCK or some fatal error. - private boolean handleInput() { - while (isRunning()) { - final int bytesRead; - - try { - bytesRead = readPacket(mFd, mBuffer); - if (bytesRead < 1) { - if (isRunning()) logError("Socket closed, exiting", null); - break; - } - mPacketsReceived++; - } catch (ErrnoException e) { - if (e.errno == OsConstants.EAGAIN) { - // We've read everything there is to read this time around. - return true; - } else if (e.errno == OsConstants.EINTR) { - continue; - } else { - if (isRunning()) logError("readPacket error: ", e); - break; - } - } catch (Exception e) { - if (isRunning()) logError("readPacket error: ", e); - break; - } - - try { - handlePacket(mBuffer, bytesRead); - } catch (Exception e) { - logError("handlePacket error: ", e); - break; - } - } - - return false; - } - - private void unregisterAndDestroyFd() { - if (mFd == null) return; - - mQueue.removeOnFileDescriptorEventListener(mFd); - closeFd(mFd); - mFd = null; - onStop(); - } - - private boolean onCorrectThread() { - return (mHandler.getLooper() == Looper.myLooper()); - } -} diff --git a/src/android/net/util/PacketReader.java b/src/android/net/util/PacketReader.java deleted file mode 100644 index 0be7187..0000000 --- a/src/android/net/util/PacketReader.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2018 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 android.net.util; - -import static java.lang.Math.max; - -import android.os.Handler; -import android.system.Os; - -import java.io.FileDescriptor; - -/** - * Specialization of {@link FdEventsReader} that reads packets into a byte array. - * - * TODO: rename this class to something more correctly descriptive (something - * like [or less horrible than] FdReadEventsHandler?). - */ -public abstract class PacketReader extends FdEventsReader<byte[]> { - - public static final int DEFAULT_RECV_BUF_SIZE = 2 * 1024; - - protected PacketReader(Handler h) { - this(h, DEFAULT_RECV_BUF_SIZE); - } - - protected PacketReader(Handler h, int recvBufSize) { - super(h, new byte[max(recvBufSize, DEFAULT_RECV_BUF_SIZE)]); - } - - @Override - protected final int recvBufSize(byte[] buffer) { - return buffer.length; - } - - /** - * Subclasses MAY override this to change the default read() implementation - * in favour of, say, recvfrom(). - * - * Implementations MUST return the bytes read or throw an Exception. - */ - @Override - protected int readPacket(FileDescriptor fd, byte[] packetBuffer) throws Exception { - return Os.read(fd, packetBuffer, 0, packetBuffer.length); - } -} |