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:
Hugo Benichi
2016-04-14 08:08:54 +00:00
committed by android-build-merger
2 changed files with 111 additions and 3 deletions

View 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);
}
}

View File

@@ -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);
} }