blob: 649257ae3b5feaec6e9961ef0d6ed28d38d12979 [file] [log] [blame]
Erik Kline473355f2016-10-19 17:42:01 +09001/*
2 * Copyright (C) 2016 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
17package android.net.ip;
18
Remi NGUYEN VAN811f6382019-01-20 12:08:21 +090019import static android.net.util.SocketUtils.makePacketSocketAddress;
Remi NGUYEN VANe7e9f2b2019-01-18 19:05:29 +090020import static android.system.OsConstants.AF_PACKET;
21import static android.system.OsConstants.ARPHRD_ETHER;
22import static android.system.OsConstants.ETH_P_ALL;
Remi NGUYEN VAN231b52b2019-01-29 15:38:52 +090023import static android.system.OsConstants.SOCK_NONBLOCK;
Remi NGUYEN VANe7e9f2b2019-01-18 19:05:29 +090024import static android.system.OsConstants.SOCK_RAW;
Erik Kline473355f2016-10-19 17:42:01 +090025
Erik Kline473355f2016-10-19 17:42:01 +090026import android.net.util.ConnectivityPacketSummary;
Erik Kline8bd00d52017-12-08 17:47:50 +090027import android.net.util.InterfaceParams;
Remi NGUYEN VANe7e9f2b2019-01-18 19:05:29 +090028import android.net.util.PacketReader;
Remi NGUYEN VAN231b52b2019-01-29 15:38:52 +090029import android.net.util.SocketUtils;
Erik Kline473355f2016-10-19 17:42:01 +090030import android.os.Handler;
31import android.system.ErrnoException;
32import android.system.Os;
Erik Klinee42502d2017-10-04 20:28:54 +090033import android.text.TextUtils;
Erik Kline473355f2016-10-19 17:42:01 +090034import android.util.LocalLog;
Remi NGUYEN VANe7e9f2b2019-01-18 19:05:29 +090035import android.util.Log;
Erik Kline473355f2016-10-19 17:42:01 +090036
Remi NGUYEN VAN231b52b2019-01-29 15:38:52 +090037import com.android.internal.util.HexDump;
Erik Kline473355f2016-10-19 17:42:01 +090038
39import java.io.FileDescriptor;
Erik Kline473355f2016-10-19 17:42:01 +090040import java.io.IOException;
Erik Kline473355f2016-10-19 17:42:01 +090041
42
43/**
44 * Critical connectivity packet tracking daemon.
45 *
46 * Tracks ARP, DHCPv4, and IPv6 RS/RA/NS/NA packets.
47 *
48 * This class's constructor, start() and stop() methods must only be called
49 * from the same thread on which the passed in |log| is accessed.
50 *
51 * Log lines include a hexdump of the packet, which can be decoded via:
52 *
53 * echo -n H3XSTR1NG | sed -e 's/\([0-9A-F][0-9A-F]\)/\1 /g' -e 's/^/000000 /'
54 * | text2pcap - -
55 * | tcpdump -n -vv -e -r -
56 *
57 * @hide
58 */
59public class ConnectivityPacketTracker {
60 private static final String TAG = ConnectivityPacketTracker.class.getSimpleName();
61 private static final boolean DBG = false;
62 private static final String MARK_START = "--- START ---";
63 private static final String MARK_STOP = "--- STOP ---";
Erik Klinee42502d2017-10-04 20:28:54 +090064 private static final String MARK_NAMED_START = "--- START (%s) ---";
65 private static final String MARK_NAMED_STOP = "--- STOP (%s) ---";
Erik Kline473355f2016-10-19 17:42:01 +090066
67 private final String mTag;
Erik Kline473355f2016-10-19 17:42:01 +090068 private final LocalLog mLog;
Erik Kline84714bf2017-05-19 09:29:48 +090069 private final PacketReader mPacketListener;
Erik Klinef840e072017-07-10 20:17:30 +090070 private boolean mRunning;
Erik Klinee42502d2017-10-04 20:28:54 +090071 private String mDisplayName;
Erik Kline473355f2016-10-19 17:42:01 +090072
Erik Kline8bd00d52017-12-08 17:47:50 +090073 public ConnectivityPacketTracker(Handler h, InterfaceParams ifParams, LocalLog log) {
74 if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams");
Erik Kline473355f2016-10-19 17:42:01 +090075
Erik Kline8bd00d52017-12-08 17:47:50 +090076 mTag = TAG + "." + ifParams.name;
Erik Kline473355f2016-10-19 17:42:01 +090077 mLog = log;
Erik Kline8bd00d52017-12-08 17:47:50 +090078 mPacketListener = new PacketListener(h, ifParams);
Erik Kline473355f2016-10-19 17:42:01 +090079 }
80
Erik Klinee42502d2017-10-04 20:28:54 +090081 public void start(String displayName) {
Erik Klinef840e072017-07-10 20:17:30 +090082 mRunning = true;
Erik Klinee42502d2017-10-04 20:28:54 +090083 mDisplayName = displayName;
Erik Kline473355f2016-10-19 17:42:01 +090084 mPacketListener.start();
85 }
86
87 public void stop() {
88 mPacketListener.stop();
Erik Klinef840e072017-07-10 20:17:30 +090089 mRunning = false;
Erik Klinee42502d2017-10-04 20:28:54 +090090 mDisplayName = null;
Erik Kline473355f2016-10-19 17:42:01 +090091 }
92
Erik Kline84714bf2017-05-19 09:29:48 +090093 private final class PacketListener extends PacketReader {
Erik Kline8bd00d52017-12-08 17:47:50 +090094 private final InterfaceParams mInterface;
Erik Kline473355f2016-10-19 17:42:01 +090095
Erik Kline8bd00d52017-12-08 17:47:50 +090096 PacketListener(Handler h, InterfaceParams ifParams) {
97 super(h, ifParams.defaultMtu);
98 mInterface = ifParams;
Erik Kline473355f2016-10-19 17:42:01 +090099 }
100
101 @Override
Erik Klinef840e072017-07-10 20:17:30 +0900102 protected FileDescriptor createFd() {
Erik Kline473355f2016-10-19 17:42:01 +0900103 FileDescriptor s = null;
104 try {
Remi NGUYEN VAN231b52b2019-01-29 15:38:52 +0900105 s = Os.socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, 0);
106 SocketUtils.attachControlPacketFilter(s, ARPHRD_ETHER);
107 SocketUtils.bindSocket(
108 s, makePacketSocketAddress((short) ETH_P_ALL, mInterface.index));
Erik Kline473355f2016-10-19 17:42:01 +0900109 } catch (ErrnoException | IOException e) {
110 logError("Failed to create packet tracking socket: ", e);
Erik Klinef840e072017-07-10 20:17:30 +0900111 closeFd(s);
Erik Kline473355f2016-10-19 17:42:01 +0900112 return null;
113 }
114 return s;
115 }
116
117 @Override
118 protected void handlePacket(byte[] recvbuf, int length) {
119 final String summary = ConnectivityPacketSummary.summarize(
Erik Kline8bd00d52017-12-08 17:47:50 +0900120 mInterface.macAddr, recvbuf, length);
Erik Kline473355f2016-10-19 17:42:01 +0900121 if (summary == null) return;
122
123 if (DBG) Log.d(mTag, summary);
Remi NGUYEN VAN231b52b2019-01-29 15:38:52 +0900124 addLogEntry(summary + "\n[" + HexDump.toHexString(recvbuf, 0, length) + "]");
Erik Kline473355f2016-10-19 17:42:01 +0900125 }
126
127 @Override
Erik Klinef840e072017-07-10 20:17:30 +0900128 protected void onStart() {
Erik Klinee42502d2017-10-04 20:28:54 +0900129 final String msg = TextUtils.isEmpty(mDisplayName)
130 ? MARK_START
131 : String.format(MARK_NAMED_START, mDisplayName);
132 mLog.log(msg);
Erik Klinef840e072017-07-10 20:17:30 +0900133 }
134
135 @Override
136 protected void onStop() {
Erik Klinee42502d2017-10-04 20:28:54 +0900137 String msg = TextUtils.isEmpty(mDisplayName)
138 ? MARK_STOP
139 : String.format(MARK_NAMED_STOP, mDisplayName);
140 if (!mRunning) msg += " (packet listener stopped unexpectedly)";
141 mLog.log(msg);
Erik Klinef840e072017-07-10 20:17:30 +0900142 }
143
144 @Override
Erik Kline473355f2016-10-19 17:42:01 +0900145 protected void logError(String msg, Exception e) {
146 Log.e(mTag, msg, e);
147 addLogEntry(msg + e);
148 }
149
150 private void addLogEntry(String entry) {
Erik Klinef840e072017-07-10 20:17:30 +0900151 mLog.log(entry);
Erik Kline473355f2016-10-19 17:42:01 +0900152 }
153 }
154}