1473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline/*
2473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * Copyright (C) 2016 The Android Open Source Project
3473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline *
4473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * Licensed under the Apache License, Version 2.0 (the "License");
5473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * you may not use this file except in compliance with the License.
6473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * You may obtain a copy of the License at
7473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline *
8473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline *      http://www.apache.org/licenses/LICENSE-2.0
9473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline *
10473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * Unless required by applicable law or agreed to in writing, software
11473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * distributed under the License is distributed on an "AS IS" BASIS,
12473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * See the License for the specific language governing permissions and
14473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * limitations under the License.
15473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline */
16473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline
17473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klinepackage android.net.ip;
18473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline
19473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport static android.system.OsConstants.*;
20473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline
21473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport android.net.NetworkUtils;
2284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport android.net.util.PacketReader;
23473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport android.net.util.ConnectivityPacketSummary;
248bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Klineimport android.net.util.InterfaceParams;
25473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport android.os.Handler;
26473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport android.system.ErrnoException;
27473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport android.system.Os;
28473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport android.system.PacketSocketAddress;
29e42502d2bb85b240a3d4e7ef29ad5a5d6413f29dErik Klineimport android.text.TextUtils;
30473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport android.util.Log;
31473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport android.util.LocalLog;
32473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline
33473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport libcore.io.IoBridge;
34473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport libcore.util.HexEncoding;
35473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline
36473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport java.io.FileDescriptor;
37473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport java.io.InterruptedIOException;
38473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport java.io.IOException;
39473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport java.net.SocketException;
40473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline
41473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline
42473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline/**
43473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * Critical connectivity packet tracking daemon.
44473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline *
45473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * Tracks ARP, DHCPv4, and IPv6 RS/RA/NS/NA packets.
46473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline *
47473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * This class's constructor, start() and stop() methods must only be called
48473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * from the same thread on which the passed in |log| is accessed.
49473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline *
50473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * Log lines include a hexdump of the packet, which can be decoded via:
51473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline *
52473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline *     echo -n H3XSTR1NG | sed -e 's/\([0-9A-F][0-9A-F]\)/\1 /g' -e 's/^/000000 /'
53473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline *                       | text2pcap - -
54473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline *                       | tcpdump -n -vv -e -r -
55473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline *
56473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * @hide
57473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline */
58473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klinepublic class ConnectivityPacketTracker {
59473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline    private static final String TAG = ConnectivityPacketTracker.class.getSimpleName();
60473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline    private static final boolean DBG = false;
61473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline    private static final String MARK_START = "--- START ---";
62473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline    private static final String MARK_STOP = "--- STOP ---";
63e42502d2bb85b240a3d4e7ef29ad5a5d6413f29dErik Kline    private static final String MARK_NAMED_START = "--- START (%s) ---";
64e42502d2bb85b240a3d4e7ef29ad5a5d6413f29dErik Kline    private static final String MARK_NAMED_STOP = "--- STOP (%s) ---";
65473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline
66473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline    private final String mTag;
67473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline    private final LocalLog mLog;
6884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline    private final PacketReader mPacketListener;
69f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline    private boolean mRunning;
70e42502d2bb85b240a3d4e7ef29ad5a5d6413f29dErik Kline    private String mDisplayName;
71473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline
728bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline    public ConnectivityPacketTracker(Handler h, InterfaceParams ifParams, LocalLog log) {
738bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline        if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams");
74473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline
758bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline        mTag = TAG + "." + ifParams.name;
76473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline        mLog = log;
778bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline        mPacketListener = new PacketListener(h, ifParams);
78473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline    }
79473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline
80e42502d2bb85b240a3d4e7ef29ad5a5d6413f29dErik Kline    public void start(String displayName) {
81f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        mRunning = true;
82e42502d2bb85b240a3d4e7ef29ad5a5d6413f29dErik Kline        mDisplayName = displayName;
83473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline        mPacketListener.start();
84473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline    }
85473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline
86473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline    public void stop() {
87473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline        mPacketListener.stop();
88f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        mRunning = false;
89e42502d2bb85b240a3d4e7ef29ad5a5d6413f29dErik Kline        mDisplayName = null;
90473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline    }
91473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline
9284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline    private final class PacketListener extends PacketReader {
938bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline        private final InterfaceParams mInterface;
94473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline
958bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline        PacketListener(Handler h, InterfaceParams ifParams) {
968bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline            super(h, ifParams.defaultMtu);
978bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline            mInterface = ifParams;
98473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline        }
99473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline
100473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline        @Override
101f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        protected FileDescriptor createFd() {
102473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline            FileDescriptor s = null;
103473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline            try {
104473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline                s = Os.socket(AF_PACKET, SOCK_RAW, 0);
105473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline                NetworkUtils.attachControlPacketFilter(s, ARPHRD_ETHER);
1068bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline                Os.bind(s, new PacketSocketAddress((short) ETH_P_ALL, mInterface.index));
107473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline            } catch (ErrnoException | IOException e) {
108473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline                logError("Failed to create packet tracking socket: ", e);
109f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline                closeFd(s);
110473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline                return null;
111473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline            }
112473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline            return s;
113473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline        }
114473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline
115473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline        @Override
116473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline        protected void handlePacket(byte[] recvbuf, int length) {
117473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline            final String summary = ConnectivityPacketSummary.summarize(
1188bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline                    mInterface.macAddr, recvbuf, length);
119473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline            if (summary == null) return;
120473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline
121473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline            if (DBG) Log.d(mTag, summary);
122473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline            addLogEntry(summary +
123473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline                        "\n[" + new String(HexEncoding.encode(recvbuf, 0, length)) + "]");
124473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline        }
125473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline
126473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline        @Override
127f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        protected void onStart() {
128e42502d2bb85b240a3d4e7ef29ad5a5d6413f29dErik Kline            final String msg = TextUtils.isEmpty(mDisplayName)
129e42502d2bb85b240a3d4e7ef29ad5a5d6413f29dErik Kline                    ? MARK_START
130e42502d2bb85b240a3d4e7ef29ad5a5d6413f29dErik Kline                    : String.format(MARK_NAMED_START, mDisplayName);
131e42502d2bb85b240a3d4e7ef29ad5a5d6413f29dErik Kline            mLog.log(msg);
132f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        }
133f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline
134f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        @Override
135f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        protected void onStop() {
136e42502d2bb85b240a3d4e7ef29ad5a5d6413f29dErik Kline            String msg = TextUtils.isEmpty(mDisplayName)
137e42502d2bb85b240a3d4e7ef29ad5a5d6413f29dErik Kline                    ? MARK_STOP
138e42502d2bb85b240a3d4e7ef29ad5a5d6413f29dErik Kline                    : String.format(MARK_NAMED_STOP, mDisplayName);
139e42502d2bb85b240a3d4e7ef29ad5a5d6413f29dErik Kline            if (!mRunning) msg += " (packet listener stopped unexpectedly)";
140e42502d2bb85b240a3d4e7ef29ad5a5d6413f29dErik Kline            mLog.log(msg);
141f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        }
142f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline
143f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        @Override
144473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline        protected void logError(String msg, Exception e) {
145473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline            Log.e(mTag, msg, e);
146473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline            addLogEntry(msg + e);
147473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline        }
148473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline
149473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline        private void addLogEntry(String entry) {
150f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline            mLog.log(entry);
151473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline        }
152473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline    }
153473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline}
154