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.net.util.SocketUtils.makePacketSocketAddress; 20 import static android.system.OsConstants.AF_PACKET; 21 import static android.system.OsConstants.ARPHRD_ETHER; 22 import static android.system.OsConstants.ETH_P_ALL; 23 import static android.system.OsConstants.SOCK_NONBLOCK; 24 import static android.system.OsConstants.SOCK_RAW; 25 26 import android.net.util.ConnectivityPacketSummary; 27 import android.net.util.InterfaceParams; 28 import android.net.util.NetworkStackUtils; 29 import android.os.Handler; 30 import android.os.SystemClock; 31 import android.system.ErrnoException; 32 import android.system.Os; 33 import android.text.TextUtils; 34 import android.util.LocalLog; 35 import android.util.Log; 36 37 import com.android.internal.util.HexDump; 38 import com.android.internal.util.TokenBucket; 39 import com.android.net.module.util.PacketReader; 40 41 import java.io.FileDescriptor; 42 import java.io.IOException; 43 44 45 /** 46 * Critical connectivity packet tracking daemon. 47 * 48 * Tracks ARP, DHCPv4, and IPv6 RS/RA/NS/NA packets. 49 * 50 * This class's constructor, start() and stop() methods must only be called 51 * from the same thread on which the passed in |log| is accessed. 52 * 53 * Log lines include a hexdump of the packet, which can be decoded via: 54 * 55 * echo -n H3XSTR1NG | sed -e 's/\([0-9A-F][0-9A-F]\)/\1 /g' -e 's/^/000000 /' 56 * | text2pcap - - 57 * | tcpdump -n -vv -e -r - 58 * 59 * @hide 60 */ 61 public class ConnectivityPacketTracker { 62 private static final String TAG = ConnectivityPacketTracker.class.getSimpleName(); 63 private static final boolean DBG = false; 64 private static final String MARK_START = "--- START ---"; 65 private static final String MARK_STOP = "--- STOP ---"; 66 private static final String MARK_NAMED_START = "--- START (%s) ---"; 67 private static final String MARK_NAMED_STOP = "--- STOP (%s) ---"; 68 // Use a TokenBucket to limit CPU usage of logging packets in steady state. 69 private static final int TOKEN_FILL_RATE = 50; // Maximum one packet every 20ms. 70 private static final int MAX_BURST_LENGTH = 100; // Maximum burst 100 packets. 71 72 private final String mTag; 73 private final LocalLog mLog; 74 private final PacketReader mPacketListener; 75 private final TokenBucket mTokenBucket = new TokenBucket(TOKEN_FILL_RATE, MAX_BURST_LENGTH); 76 private long mLastRateLimitLogTimeMs = 0; 77 private boolean mRunning; 78 private String mDisplayName; 79 ConnectivityPacketTracker(Handler h, InterfaceParams ifParams, LocalLog log)80 public ConnectivityPacketTracker(Handler h, InterfaceParams ifParams, LocalLog log) { 81 if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams"); 82 83 mTag = TAG + "." + ifParams.name; 84 mLog = log; 85 mPacketListener = new PacketListener(h, ifParams); 86 } 87 start(String displayName)88 public void start(String displayName) { 89 mRunning = true; 90 mDisplayName = displayName; 91 mPacketListener.start(); 92 } 93 stop()94 public void stop() { 95 mPacketListener.stop(); 96 mRunning = false; 97 mDisplayName = null; 98 } 99 100 private final class PacketListener extends PacketReader { 101 private final InterfaceParams mInterface; 102 PacketListener(Handler h, InterfaceParams ifParams)103 PacketListener(Handler h, InterfaceParams ifParams) { 104 super(h, ifParams.defaultMtu); 105 mInterface = ifParams; 106 } 107 108 @Override createFd()109 protected FileDescriptor createFd() { 110 FileDescriptor s = null; 111 try { 112 s = Os.socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, 0); 113 NetworkStackUtils.attachControlPacketFilter(s, ARPHRD_ETHER); 114 Os.bind(s, makePacketSocketAddress(ETH_P_ALL, mInterface.index)); 115 } catch (ErrnoException | IOException e) { 116 logError("Failed to create packet tracking socket: ", e); 117 closeFd(s); 118 return null; 119 } 120 return s; 121 } 122 123 @Override handlePacket(byte[] recvbuf, int length)124 protected void handlePacket(byte[] recvbuf, int length) { 125 if (!mTokenBucket.get()) { 126 // Rate limited. Log once every second so the user knows packets are missing. 127 final long now = SystemClock.elapsedRealtime(); 128 if (now >= mLastRateLimitLogTimeMs + 1000) { 129 addLogEntry("Warning: too many packets, rate-limiting to one every " + 130 TOKEN_FILL_RATE + "ms"); 131 mLastRateLimitLogTimeMs = now; 132 } 133 return; 134 } 135 136 final String summary; 137 try { 138 summary = ConnectivityPacketSummary.summarize(mInterface.macAddr, recvbuf, length); 139 if (summary == null) return; 140 } catch (Exception e) { 141 if (DBG) Log.d(mTag, "Error creating packet summary", e); 142 return; 143 } 144 145 if (DBG) Log.d(mTag, summary); 146 addLogEntry(summary + "\n[" + HexDump.toHexString(recvbuf, 0, length) + "]"); 147 } 148 149 @Override onStart()150 protected void onStart() { 151 final String msg = TextUtils.isEmpty(mDisplayName) 152 ? MARK_START 153 : String.format(MARK_NAMED_START, mDisplayName); 154 mLog.log(msg); 155 } 156 157 @Override onStop()158 protected void onStop() { 159 String msg = TextUtils.isEmpty(mDisplayName) 160 ? MARK_STOP 161 : String.format(MARK_NAMED_STOP, mDisplayName); 162 if (!mRunning) msg += " (packet listener stopped unexpectedly)"; 163 mLog.log(msg); 164 } 165 166 @Override logError(String msg, Exception e)167 protected void logError(String msg, Exception e) { 168 Log.e(mTag, msg, e); 169 addLogEntry(msg + e); 170 } 171 addLogEntry(String entry)172 private void addLogEntry(String entry) { 173 mLog.log(entry); 174 } 175 } 176 } 177