Home | History | Annotate | Download | only in ip
      1 /*
      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 
     17 package android.net.ip;
     18 
     19 import static android.system.OsConstants.*;
     20 
     21 import android.net.NetworkUtils;
     22 import android.net.util.PacketReader;
     23 import android.net.util.ConnectivityPacketSummary;
     24 import android.net.util.InterfaceParams;
     25 import android.os.Handler;
     26 import android.system.ErrnoException;
     27 import android.system.Os;
     28 import android.system.PacketSocketAddress;
     29 import android.text.TextUtils;
     30 import android.util.Log;
     31 import android.util.LocalLog;
     32 
     33 import libcore.io.IoBridge;
     34 import libcore.util.HexEncoding;
     35 
     36 import java.io.FileDescriptor;
     37 import java.io.InterruptedIOException;
     38 import java.io.IOException;
     39 import java.net.SocketException;
     40 
     41 
     42 /**
     43  * Critical connectivity packet tracking daemon.
     44  *
     45  * Tracks ARP, DHCPv4, and IPv6 RS/RA/NS/NA packets.
     46  *
     47  * This class's constructor, start() and stop() methods must only be called
     48  * from the same thread on which the passed in |log| is accessed.
     49  *
     50  * Log lines include a hexdump of the packet, which can be decoded via:
     51  *
     52  *     echo -n H3XSTR1NG | sed -e 's/\([0-9A-F][0-9A-F]\)/\1 /g' -e 's/^/000000 /'
     53  *                       | text2pcap - -
     54  *                       | tcpdump -n -vv -e -r -
     55  *
     56  * @hide
     57  */
     58 public class ConnectivityPacketTracker {
     59     private static final String TAG = ConnectivityPacketTracker.class.getSimpleName();
     60     private static final boolean DBG = false;
     61     private static final String MARK_START = "--- START ---";
     62     private static final String MARK_STOP = "--- STOP ---";
     63     private static final String MARK_NAMED_START = "--- START (%s) ---";
     64     private static final String MARK_NAMED_STOP = "--- STOP (%s) ---";
     65 
     66     private final String mTag;
     67     private final LocalLog mLog;
     68     private final PacketReader mPacketListener;
     69     private boolean mRunning;
     70     private String mDisplayName;
     71 
     72     public ConnectivityPacketTracker(Handler h, InterfaceParams ifParams, LocalLog log) {
     73         if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams");
     74 
     75         mTag = TAG + "." + ifParams.name;
     76         mLog = log;
     77         mPacketListener = new PacketListener(h, ifParams);
     78     }
     79 
     80     public void start(String displayName) {
     81         mRunning = true;
     82         mDisplayName = displayName;
     83         mPacketListener.start();
     84     }
     85 
     86     public void stop() {
     87         mPacketListener.stop();
     88         mRunning = false;
     89         mDisplayName = null;
     90     }
     91 
     92     private final class PacketListener extends PacketReader {
     93         private final InterfaceParams mInterface;
     94 
     95         PacketListener(Handler h, InterfaceParams ifParams) {
     96             super(h, ifParams.defaultMtu);
     97             mInterface = ifParams;
     98         }
     99 
    100         @Override
    101         protected FileDescriptor createFd() {
    102             FileDescriptor s = null;
    103             try {
    104                 s = Os.socket(AF_PACKET, SOCK_RAW, 0);
    105                 NetworkUtils.attachControlPacketFilter(s, ARPHRD_ETHER);
    106                 Os.bind(s, new PacketSocketAddress((short) ETH_P_ALL, mInterface.index));
    107             } catch (ErrnoException | IOException e) {
    108                 logError("Failed to create packet tracking socket: ", e);
    109                 closeFd(s);
    110                 return null;
    111             }
    112             return s;
    113         }
    114 
    115         @Override
    116         protected void handlePacket(byte[] recvbuf, int length) {
    117             final String summary = ConnectivityPacketSummary.summarize(
    118                     mInterface.macAddr, recvbuf, length);
    119             if (summary == null) return;
    120 
    121             if (DBG) Log.d(mTag, summary);
    122             addLogEntry(summary +
    123                         "\n[" + new String(HexEncoding.encode(recvbuf, 0, length)) + "]");
    124         }
    125 
    126         @Override
    127         protected void onStart() {
    128             final String msg = TextUtils.isEmpty(mDisplayName)
    129                     ? MARK_START
    130                     : String.format(MARK_NAMED_START, mDisplayName);
    131             mLog.log(msg);
    132         }
    133 
    134         @Override
    135         protected void onStop() {
    136             String msg = TextUtils.isEmpty(mDisplayName)
    137                     ? MARK_STOP
    138                     : String.format(MARK_NAMED_STOP, mDisplayName);
    139             if (!mRunning) msg += " (packet listener stopped unexpectedly)";
    140             mLog.log(msg);
    141         }
    142 
    143         @Override
    144         protected void logError(String msg, Exception e) {
    145             Log.e(mTag, msg, e);
    146             addLogEntry(msg + e);
    147         }
    148 
    149         private void addLogEntry(String entry) {
    150             mLog.log(entry);
    151         }
    152     }
    153 }
    154