Merge "Add DHCP error event class and record DHCP errors." into nyc-dev
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.LinkAddress;
|
||||
import android.net.NetworkUtils;
|
||||
import android.net.metrics.DhcpErrorEvent;
|
||||
import android.os.Build;
|
||||
import android.os.SystemProperties;
|
||||
import android.system.OsConstants;
|
||||
@@ -765,6 +766,7 @@ abstract class DhcpPacket {
|
||||
// check to see if we need to parse L2, IP, and UDP encaps
|
||||
if (pktType == ENCAP_L2) {
|
||||
if (packet.remaining() < MIN_PACKET_LENGTH_L2) {
|
||||
DhcpErrorEvent.logEvent(DhcpErrorEvent.L2_TOO_SHORT);
|
||||
throw new ParseException("L2 packet too short, %d < %d",
|
||||
packet.remaining(), MIN_PACKET_LENGTH_L2);
|
||||
}
|
||||
@@ -777,13 +779,16 @@ abstract class DhcpPacket {
|
||||
|
||||
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",
|
||||
l2type, OsConstants.ETH_P_IP);
|
||||
}
|
||||
}
|
||||
|
||||
if (pktType <= ENCAP_L3) {
|
||||
if (packet.remaining() < MIN_PACKET_LENGTH_L3) {
|
||||
DhcpErrorEvent.logEvent(DhcpErrorEvent.L3_TOO_SHORT);
|
||||
throw new ParseException("L3 packet too short, %d < %d",
|
||||
packet.remaining(), MIN_PACKET_LENGTH_L3);
|
||||
}
|
||||
@@ -791,6 +796,7 @@ abstract class DhcpPacket {
|
||||
byte ipTypeAndLength = packet.get();
|
||||
int ipVersion = (ipTypeAndLength & 0xf0) >> 4;
|
||||
if (ipVersion != 4) {
|
||||
DhcpErrorEvent.logEvent(DhcpErrorEvent.L3_NOT_IPV4);
|
||||
throw new ParseException("Invalid IP version %d", ipVersion);
|
||||
}
|
||||
|
||||
@@ -808,6 +814,7 @@ abstract class DhcpPacket {
|
||||
ipDst = readIpAddress(packet);
|
||||
|
||||
if (ipProto != IP_TYPE_UDP) {
|
||||
DhcpErrorEvent.logEvent(DhcpErrorEvent.L4_NOT_UDP);
|
||||
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
|
||||
// possible that a packet arrives between when the socket is bound and when the
|
||||
// filter is set. http://b/26696823 .
|
||||
DhcpErrorEvent.logEvent(DhcpErrorEvent.L4_WRONG_PORT);
|
||||
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.
|
||||
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",
|
||||
packet.remaining(), MIN_PACKET_LENGTH_BOOTP);
|
||||
}
|
||||
@@ -864,6 +873,7 @@ abstract class DhcpPacket {
|
||||
packet.get(ipv4addr);
|
||||
relayIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
|
||||
} catch (UnknownHostException ex) {
|
||||
DhcpErrorEvent.logEvent(DhcpErrorEvent.L3_INVALID_IP);
|
||||
throw new ParseException("Invalid IPv4 address: %s", Arrays.toString(ipv4addr));
|
||||
}
|
||||
|
||||
@@ -888,6 +898,7 @@ abstract class DhcpPacket {
|
||||
int dhcpMagicCookie = packet.getInt();
|
||||
|
||||
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,
|
||||
DHCP_MAGIC_COOKIE);
|
||||
}
|
||||
@@ -896,9 +907,8 @@ abstract class DhcpPacket {
|
||||
boolean notFinishedOptions = true;
|
||||
|
||||
while ((packet.position() < packet.limit()) && notFinishedOptions) {
|
||||
final byte optionType = packet.get(); // cannot underflow because position < limit
|
||||
try {
|
||||
byte optionType = packet.get();
|
||||
|
||||
if (optionType == DHCP_OPTION_END) {
|
||||
notFinishedOptions = false;
|
||||
} else if (optionType == DHCP_OPTION_PAD) {
|
||||
@@ -999,11 +1009,14 @@ abstract class DhcpPacket {
|
||||
}
|
||||
|
||||
if (expectedLen != optionLen) {
|
||||
DhcpErrorEvent.logEvent(
|
||||
DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH, optionType);
|
||||
throw new ParseException("Invalid length %d for option %d, expected %d",
|
||||
optionLen, optionType, expectedLen);
|
||||
}
|
||||
}
|
||||
} catch (BufferUnderflowException e) {
|
||||
DhcpErrorEvent.logEvent(DhcpErrorEvent.BUFFER_UNDERFLOW, optionType);
|
||||
throw new ParseException("BufferUnderflowException");
|
||||
}
|
||||
}
|
||||
@@ -1012,6 +1025,7 @@ abstract class DhcpPacket {
|
||||
|
||||
switch(dhcpType) {
|
||||
case (byte) 0xFF:
|
||||
DhcpErrorEvent.logEvent(DhcpErrorEvent.DHCP_NO_MSG_TYPE);
|
||||
throw new ParseException("No DHCP message type option");
|
||||
case DHCP_MESSAGE_TYPE_DISCOVER:
|
||||
newPacket = new DhcpDiscoverPacket(
|
||||
@@ -1045,6 +1059,7 @@ abstract class DhcpPacket {
|
||||
clientMac);
|
||||
break;
|
||||
default:
|
||||
DhcpErrorEvent.logEvent(DhcpErrorEvent.DHCP_UNKNOWN_MSG_TYPE);
|
||||
throw new ParseException("Unimplemented DHCP type %d", dhcpType);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user