Merge "Add DHCP error event class and record DHCP errors." into nyc-dev
am: fc18b6f
* commit 'fc18b6f3608d87f3dc53cda8d8db30636c92d6e9':
Add DHCP error event class and record DHCP errors.
Change-Id: I5b9ef8b191ab0ef4349ed00c1d8f548393aba368
This commit is contained in:
93
core/java/android/net/metrics/DhcpErrorEvent.java
Normal file
93
core/java/android/net/metrics/DhcpErrorEvent.java
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* 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.metrics;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@hide} Event class used to record error events when parsing DHCP response packets.
|
||||||
|
*/
|
||||||
|
public class DhcpErrorEvent extends IpConnectivityEvent implements Parcelable {
|
||||||
|
public static final String TAG = "DhcpErrorEvent";
|
||||||
|
|
||||||
|
public static final int L2_ERROR = 1;
|
||||||
|
public static final int L3_ERROR = 2;
|
||||||
|
public static final int L4_ERROR = 3;
|
||||||
|
public static final int DHCP_ERROR = 4;
|
||||||
|
public static final int MISC_ERROR = 5;
|
||||||
|
|
||||||
|
public static final int L2_TOO_SHORT = makeErrorCode(L2_ERROR, 1);
|
||||||
|
public static final int L2_WRONG_ETH_TYPE = makeErrorCode(L2_ERROR, 2);
|
||||||
|
|
||||||
|
public static final int L3_TOO_SHORT = makeErrorCode(L3_ERROR, 1);
|
||||||
|
public static final int L3_NOT_IPV4 = makeErrorCode(L3_ERROR, 2);
|
||||||
|
public static final int L3_INVALID_IP = makeErrorCode(L3_ERROR, 3);
|
||||||
|
|
||||||
|
public static final int L4_NOT_UDP = makeErrorCode(L4_ERROR, 1);
|
||||||
|
public static final int L4_WRONG_PORT = makeErrorCode(L4_ERROR, 2);
|
||||||
|
|
||||||
|
public static final int BOOTP_TOO_SHORT = makeErrorCode(DHCP_ERROR, 1);
|
||||||
|
public static final int DHCP_BAD_MAGIC_COOKIE = makeErrorCode(DHCP_ERROR, 2);
|
||||||
|
public static final int DHCP_INVALID_OPTION_LENGTH = makeErrorCode(DHCP_ERROR, 3);
|
||||||
|
public static final int DHCP_NO_MSG_TYPE = makeErrorCode(DHCP_ERROR, 4);
|
||||||
|
public static final int DHCP_UNKNOWN_MSG_TYPE = makeErrorCode(DHCP_ERROR, 5);
|
||||||
|
|
||||||
|
public static final int BUFFER_UNDERFLOW = makeErrorCode(MISC_ERROR, 1);
|
||||||
|
|
||||||
|
// error code byte format (MSB to LSB):
|
||||||
|
// byte 0: error type
|
||||||
|
// byte 1: error subtype
|
||||||
|
// byte 2: unused
|
||||||
|
// byte 3: optional code
|
||||||
|
public final int errorCode;
|
||||||
|
|
||||||
|
private DhcpErrorEvent(int errorCode) {
|
||||||
|
this.errorCode = errorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DhcpErrorEvent(Parcel in) {
|
||||||
|
this.errorCode = in.readInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeToParcel(Parcel out, int flags) {
|
||||||
|
out.writeInt(errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<DhcpErrorEvent> CREATOR
|
||||||
|
= new Parcelable.Creator<DhcpErrorEvent>() {
|
||||||
|
public DhcpErrorEvent createFromParcel(Parcel in) {
|
||||||
|
return new DhcpErrorEvent(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DhcpErrorEvent[] newArray(int size) {
|
||||||
|
return new DhcpErrorEvent[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static void logEvent(int errorCode) {
|
||||||
|
IpConnectivityEvent.logEvent(IPCE_DHCP_PARSE_ERROR, new DhcpErrorEvent(errorCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void logEvent(int errorCode, int option) {
|
||||||
|
logEvent((0xFFFF0000 & errorCode) | (0xFF & option));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int makeErrorCode(int type, int subtype) {
|
||||||
|
return (type << 24) | ((0xFF & subtype) << 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package android.net.dhcp;
|
|||||||
import android.net.DhcpResults;
|
import android.net.DhcpResults;
|
||||||
import android.net.LinkAddress;
|
import android.net.LinkAddress;
|
||||||
import android.net.NetworkUtils;
|
import android.net.NetworkUtils;
|
||||||
|
import android.net.metrics.DhcpErrorEvent;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.SystemProperties;
|
import android.os.SystemProperties;
|
||||||
import android.system.OsConstants;
|
import android.system.OsConstants;
|
||||||
@@ -765,6 +766,7 @@ abstract class DhcpPacket {
|
|||||||
// check to see if we need to parse L2, IP, and UDP encaps
|
// check to see if we need to parse L2, IP, and UDP encaps
|
||||||
if (pktType == ENCAP_L2) {
|
if (pktType == ENCAP_L2) {
|
||||||
if (packet.remaining() < MIN_PACKET_LENGTH_L2) {
|
if (packet.remaining() < MIN_PACKET_LENGTH_L2) {
|
||||||
|
DhcpErrorEvent.logEvent(DhcpErrorEvent.L2_TOO_SHORT);
|
||||||
throw new ParseException("L2 packet too short, %d < %d",
|
throw new ParseException("L2 packet too short, %d < %d",
|
||||||
packet.remaining(), MIN_PACKET_LENGTH_L2);
|
packet.remaining(), MIN_PACKET_LENGTH_L2);
|
||||||
}
|
}
|
||||||
@@ -777,13 +779,16 @@ abstract class DhcpPacket {
|
|||||||
|
|
||||||
short l2type = packet.getShort();
|
short l2type = packet.getShort();
|
||||||
|
|
||||||
if (l2type != OsConstants.ETH_P_IP)
|
if (l2type != OsConstants.ETH_P_IP) {
|
||||||
|
DhcpErrorEvent.logEvent(DhcpErrorEvent.L2_WRONG_ETH_TYPE);
|
||||||
throw new ParseException("Unexpected L2 type 0x%04x, expected 0x%04x",
|
throw new ParseException("Unexpected L2 type 0x%04x, expected 0x%04x",
|
||||||
l2type, OsConstants.ETH_P_IP);
|
l2type, OsConstants.ETH_P_IP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pktType <= ENCAP_L3) {
|
if (pktType <= ENCAP_L3) {
|
||||||
if (packet.remaining() < MIN_PACKET_LENGTH_L3) {
|
if (packet.remaining() < MIN_PACKET_LENGTH_L3) {
|
||||||
|
DhcpErrorEvent.logEvent(DhcpErrorEvent.L3_TOO_SHORT);
|
||||||
throw new ParseException("L3 packet too short, %d < %d",
|
throw new ParseException("L3 packet too short, %d < %d",
|
||||||
packet.remaining(), MIN_PACKET_LENGTH_L3);
|
packet.remaining(), MIN_PACKET_LENGTH_L3);
|
||||||
}
|
}
|
||||||
@@ -791,6 +796,7 @@ abstract class DhcpPacket {
|
|||||||
byte ipTypeAndLength = packet.get();
|
byte ipTypeAndLength = packet.get();
|
||||||
int ipVersion = (ipTypeAndLength & 0xf0) >> 4;
|
int ipVersion = (ipTypeAndLength & 0xf0) >> 4;
|
||||||
if (ipVersion != 4) {
|
if (ipVersion != 4) {
|
||||||
|
DhcpErrorEvent.logEvent(DhcpErrorEvent.L3_NOT_IPV4);
|
||||||
throw new ParseException("Invalid IP version %d", ipVersion);
|
throw new ParseException("Invalid IP version %d", ipVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -808,6 +814,7 @@ abstract class DhcpPacket {
|
|||||||
ipDst = readIpAddress(packet);
|
ipDst = readIpAddress(packet);
|
||||||
|
|
||||||
if (ipProto != IP_TYPE_UDP) {
|
if (ipProto != IP_TYPE_UDP) {
|
||||||
|
DhcpErrorEvent.logEvent(DhcpErrorEvent.L4_NOT_UDP);
|
||||||
throw new ParseException("Protocol not UDP: %d", ipProto);
|
throw new ParseException("Protocol not UDP: %d", ipProto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -834,12 +841,14 @@ abstract class DhcpPacket {
|
|||||||
// socket to drop packets that don't have the right source ports. However, it's
|
// socket to drop packets that don't have the right source ports. However, it's
|
||||||
// possible that a packet arrives between when the socket is bound and when the
|
// possible that a packet arrives between when the socket is bound and when the
|
||||||
// filter is set. http://b/26696823 .
|
// filter is set. http://b/26696823 .
|
||||||
|
DhcpErrorEvent.logEvent(DhcpErrorEvent.L4_WRONG_PORT);
|
||||||
throw new ParseException("Unexpected UDP ports %d->%d", udpSrcPort, udpDstPort);
|
throw new ParseException("Unexpected UDP ports %d->%d", udpSrcPort, udpDstPort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to check the length even for ENCAP_L3 because the IPv4 header is variable-length.
|
// We need to check the length even for ENCAP_L3 because the IPv4 header is variable-length.
|
||||||
if (pktType > ENCAP_BOOTP || packet.remaining() < MIN_PACKET_LENGTH_BOOTP) {
|
if (pktType > ENCAP_BOOTP || packet.remaining() < MIN_PACKET_LENGTH_BOOTP) {
|
||||||
|
DhcpErrorEvent.logEvent(DhcpErrorEvent.BOOTP_TOO_SHORT);
|
||||||
throw new ParseException("Invalid type or BOOTP packet too short, %d < %d",
|
throw new ParseException("Invalid type or BOOTP packet too short, %d < %d",
|
||||||
packet.remaining(), MIN_PACKET_LENGTH_BOOTP);
|
packet.remaining(), MIN_PACKET_LENGTH_BOOTP);
|
||||||
}
|
}
|
||||||
@@ -864,6 +873,7 @@ abstract class DhcpPacket {
|
|||||||
packet.get(ipv4addr);
|
packet.get(ipv4addr);
|
||||||
relayIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
|
relayIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
|
||||||
} catch (UnknownHostException ex) {
|
} catch (UnknownHostException ex) {
|
||||||
|
DhcpErrorEvent.logEvent(DhcpErrorEvent.L3_INVALID_IP);
|
||||||
throw new ParseException("Invalid IPv4 address: %s", Arrays.toString(ipv4addr));
|
throw new ParseException("Invalid IPv4 address: %s", Arrays.toString(ipv4addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -888,6 +898,7 @@ abstract class DhcpPacket {
|
|||||||
int dhcpMagicCookie = packet.getInt();
|
int dhcpMagicCookie = packet.getInt();
|
||||||
|
|
||||||
if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) {
|
if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) {
|
||||||
|
DhcpErrorEvent.logEvent(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE);
|
||||||
throw new ParseException("Bad magic cookie 0x%08x, should be 0x%08x", dhcpMagicCookie,
|
throw new ParseException("Bad magic cookie 0x%08x, should be 0x%08x", dhcpMagicCookie,
|
||||||
DHCP_MAGIC_COOKIE);
|
DHCP_MAGIC_COOKIE);
|
||||||
}
|
}
|
||||||
@@ -896,9 +907,8 @@ abstract class DhcpPacket {
|
|||||||
boolean notFinishedOptions = true;
|
boolean notFinishedOptions = true;
|
||||||
|
|
||||||
while ((packet.position() < packet.limit()) && notFinishedOptions) {
|
while ((packet.position() < packet.limit()) && notFinishedOptions) {
|
||||||
|
final byte optionType = packet.get(); // cannot underflow because position < limit
|
||||||
try {
|
try {
|
||||||
byte optionType = packet.get();
|
|
||||||
|
|
||||||
if (optionType == DHCP_OPTION_END) {
|
if (optionType == DHCP_OPTION_END) {
|
||||||
notFinishedOptions = false;
|
notFinishedOptions = false;
|
||||||
} else if (optionType == DHCP_OPTION_PAD) {
|
} else if (optionType == DHCP_OPTION_PAD) {
|
||||||
@@ -999,11 +1009,14 @@ abstract class DhcpPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (expectedLen != optionLen) {
|
if (expectedLen != optionLen) {
|
||||||
|
DhcpErrorEvent.logEvent(
|
||||||
|
DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH, optionType);
|
||||||
throw new ParseException("Invalid length %d for option %d, expected %d",
|
throw new ParseException("Invalid length %d for option %d, expected %d",
|
||||||
optionLen, optionType, expectedLen);
|
optionLen, optionType, expectedLen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (BufferUnderflowException e) {
|
} catch (BufferUnderflowException e) {
|
||||||
|
DhcpErrorEvent.logEvent(DhcpErrorEvent.BUFFER_UNDERFLOW, optionType);
|
||||||
throw new ParseException("BufferUnderflowException");
|
throw new ParseException("BufferUnderflowException");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1012,6 +1025,7 @@ abstract class DhcpPacket {
|
|||||||
|
|
||||||
switch(dhcpType) {
|
switch(dhcpType) {
|
||||||
case (byte) 0xFF:
|
case (byte) 0xFF:
|
||||||
|
DhcpErrorEvent.logEvent(DhcpErrorEvent.DHCP_NO_MSG_TYPE);
|
||||||
throw new ParseException("No DHCP message type option");
|
throw new ParseException("No DHCP message type option");
|
||||||
case DHCP_MESSAGE_TYPE_DISCOVER:
|
case DHCP_MESSAGE_TYPE_DISCOVER:
|
||||||
newPacket = new DhcpDiscoverPacket(
|
newPacket = new DhcpDiscoverPacket(
|
||||||
@@ -1045,6 +1059,7 @@ abstract class DhcpPacket {
|
|||||||
clientMac);
|
clientMac);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
DhcpErrorEvent.logEvent(DhcpErrorEvent.DHCP_UNKNOWN_MSG_TYPE);
|
||||||
throw new ParseException("Unimplemented DHCP type %d", dhcpType);
|
throw new ParseException("Unimplemented DHCP type %d", dhcpType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user