am 871d96b4: am 13c5dd5c: am eb0bbd45: Merge changes Id6a0b0de,I5f03b8b2,I62464b92 into mnc-dr-dev

* commit '871d96b44c9665238d1df87ed89656f742abe2fa':
  Support DHCP replies with multiple default gateways.
  Accept DHCP responses from non-67 server source ports
  Improve logging of DHCP parse errors using exceptions.
This commit is contained in:
Lorenzo Colitti
2015-10-11 14:19:58 +00:00
committed by Android Git Automerger
5 changed files with 164 additions and 48 deletions

View File

@ -46,7 +46,7 @@ class DhcpAckPacket extends DhcpPacket {
return s + " ACK: your new IP " + mYourIp + return s + " ACK: your new IP " + mYourIp +
", netmask " + mSubnetMask + ", netmask " + mSubnetMask +
", gateway " + mGateway + dnsServers + ", gateways " + mGateways + dnsServers +
", lease time " + mLeaseTime; ", lease time " + mLeaseTime;
} }
@ -79,7 +79,7 @@ class DhcpAckPacket extends DhcpPacket {
} }
addTlv(buffer, DHCP_SUBNET_MASK, mSubnetMask); addTlv(buffer, DHCP_SUBNET_MASK, mSubnetMask);
addTlv(buffer, DHCP_ROUTER, mGateway); addTlv(buffer, DHCP_ROUTER, mGateways);
addTlv(buffer, DHCP_DOMAIN_NAME, mDomainName); addTlv(buffer, DHCP_DOMAIN_NAME, mDomainName);
addTlv(buffer, DHCP_BROADCAST_ADDRESS, mBroadcastAddress); addTlv(buffer, DHCP_BROADCAST_ADDRESS, mBroadcastAddress);
addTlv(buffer, DHCP_DNS_SERVER, mDnsServers); addTlv(buffer, DHCP_DNS_SERVER, mDnsServers);

View File

@ -345,21 +345,22 @@ public class DhcpClient extends BaseDhcpStateMachine {
public void run() { public void run() {
maybeLog("Receive thread started"); maybeLog("Receive thread started");
while (!stopped) { while (!stopped) {
int length = 0; // Or compiler can't tell it's initialized if a parse error occurs.
try { try {
int length = Os.read(mPacketSock, mPacket, 0, mPacket.length); length = Os.read(mPacketSock, mPacket, 0, mPacket.length);
DhcpPacket packet = null; DhcpPacket packet = null;
packet = DhcpPacket.decodeFullPacket(mPacket, length, DhcpPacket.ENCAP_L2); packet = DhcpPacket.decodeFullPacket(mPacket, length, DhcpPacket.ENCAP_L2);
if (packet != null) { maybeLog("Received packet: " + packet);
maybeLog("Received packet: " + packet); sendMessage(CMD_RECEIVED_PACKET, packet);
sendMessage(CMD_RECEIVED_PACKET, packet);
} else if (PACKET_DBG) {
Log.d(TAG,
"Can't parse packet" + HexDump.dumpHexString(mPacket, 0, length));
}
} catch (IOException|ErrnoException e) { } catch (IOException|ErrnoException e) {
if (!stopped) { if (!stopped) {
Log.e(TAG, "Read error", e); Log.e(TAG, "Read error", e);
} }
} catch (DhcpPacket.ParseException e) {
Log.e(TAG, "Can't parse packet: " + e.getMessage());
if (PACKET_DBG) {
Log.d(TAG, HexDump.dumpHexString(mPacket, 0, length));
}
} }
} }
maybeLog("Receive thread stopped"); maybeLog("Receive thread stopped");

View File

@ -48,7 +48,7 @@ class DhcpOfferPacket extends DhcpPacket {
} }
return s + " OFFER, ip " + mYourIp + ", mask " + mSubnetMask + return s + " OFFER, ip " + mYourIp + ", mask " + mSubnetMask +
dnsServers + ", gateway " + mGateway + dnsServers + ", gateways " + mGateways +
" lease time " + mLeaseTime + ", domain " + mDomainName; " lease time " + mLeaseTime + ", domain " + mDomainName;
} }
@ -81,7 +81,7 @@ class DhcpOfferPacket extends DhcpPacket {
} }
addTlv(buffer, DHCP_SUBNET_MASK, mSubnetMask); addTlv(buffer, DHCP_SUBNET_MASK, mSubnetMask);
addTlv(buffer, DHCP_ROUTER, mGateway); addTlv(buffer, DHCP_ROUTER, mGateways);
addTlv(buffer, DHCP_DOMAIN_NAME, mDomainName); addTlv(buffer, DHCP_DOMAIN_NAME, mDomainName);
addTlv(buffer, DHCP_BROADCAST_ADDRESS, mBroadcastAddress); addTlv(buffer, DHCP_BROADCAST_ADDRESS, mBroadcastAddress);
addTlv(buffer, DHCP_DNS_SERVER, mDnsServers); addTlv(buffer, DHCP_DNS_SERVER, mDnsServers);

View File

@ -113,6 +113,11 @@ abstract class DhcpPacket {
*/ */
protected static final int MAX_LENGTH = 1500; protected static final int MAX_LENGTH = 1500;
/**
* The magic cookie that identifies this as a DHCP packet instead of BOOTP.
*/
private static final int DHCP_MAGIC_COOKIE = 0x63825363;
/** /**
* DHCP Optional Type: DHCP Subnet Mask * DHCP Optional Type: DHCP Subnet Mask
*/ */
@ -123,7 +128,7 @@ abstract class DhcpPacket {
* DHCP Optional Type: DHCP Router * DHCP Optional Type: DHCP Router
*/ */
protected static final byte DHCP_ROUTER = 3; protected static final byte DHCP_ROUTER = 3;
protected Inet4Address mGateway; protected List <Inet4Address> mGateways;
/** /**
* DHCP Optional Type: DHCP DNS Server * DHCP Optional Type: DHCP DNS Server
@ -403,7 +408,7 @@ abstract class DhcpPacket {
(HWADDR_LEN - mClientMac.length) // pad addr to 16 bytes (HWADDR_LEN - mClientMac.length) // pad addr to 16 bytes
+ 64 // empty server host name (64 bytes) + 64 // empty server host name (64 bytes)
+ 128); // empty boot file name (128 bytes) + 128); // empty boot file name (128 bytes)
buf.putInt(0x63825363); // magic number buf.putInt(DHCP_MAGIC_COOKIE); // magic number
finishPacket(buf); finishPacket(buf);
// round up to an even number of octets // round up to an even number of octets
@ -668,6 +673,20 @@ abstract class DhcpPacket {
return new String(bytes, 0, length, StandardCharsets.US_ASCII); return new String(bytes, 0, length, StandardCharsets.US_ASCII);
} }
private static boolean isPacketToOrFromClient(short udpSrcPort, short udpDstPort) {
return (udpSrcPort == DHCP_CLIENT) || (udpDstPort == DHCP_CLIENT);
}
private static boolean isPacketServerToServer(short udpSrcPort, short udpDstPort) {
return (udpSrcPort == DHCP_SERVER) && (udpDstPort == DHCP_SERVER);
}
public static class ParseException extends Exception {
public ParseException(String msg, Object... args) {
super(String.format(msg, args));
}
}
/** /**
* Creates a concrete DhcpPacket from the supplied ByteBuffer. The * Creates a concrete DhcpPacket from the supplied ByteBuffer. The
* buffer may have an L2 encapsulation (which is the full EthernetII * buffer may have an L2 encapsulation (which is the full EthernetII
@ -677,7 +696,7 @@ abstract class DhcpPacket {
* A subset of the optional parameters are parsed and are stored * A subset of the optional parameters are parsed and are stored
* in object fields. * in object fields.
*/ */
public static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) public static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException
{ {
// bootp parameters // bootp parameters
int transactionId; int transactionId;
@ -687,8 +706,8 @@ abstract class DhcpPacket {
Inet4Address nextIp; Inet4Address nextIp;
Inet4Address relayIp; Inet4Address relayIp;
byte[] clientMac; byte[] clientMac;
List<Inet4Address> dnsServers = new ArrayList<Inet4Address>(); List<Inet4Address> dnsServers = new ArrayList<>();
Inet4Address gateway = null; // aka router List<Inet4Address> gateways = new ArrayList<>(); // aka router
Inet4Address serverIdentifier = null; Inet4Address serverIdentifier = null;
Inet4Address netMask = null; Inet4Address netMask = null;
String message = null; String message = null;
@ -720,7 +739,8 @@ 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) {
return null; throw new ParseException("L2 packet too short, %d < %d",
packet.remaining(), MIN_PACKET_LENGTH_L2);
} }
byte[] l2dst = new byte[6]; byte[] l2dst = new byte[6];
@ -732,18 +752,20 @@ abstract class DhcpPacket {
short l2type = packet.getShort(); short l2type = packet.getShort();
if (l2type != OsConstants.ETH_P_IP) if (l2type != OsConstants.ETH_P_IP)
return null; throw new ParseException("Unexpected L2 type 0x%04x, expected 0x%04x",
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) {
return null; throw new ParseException("L3 packet too short, %d < %d",
packet.remaining(), MIN_PACKET_LENGTH_L3);
} }
byte ipTypeAndLength = packet.get(); byte ipTypeAndLength = packet.get();
int ipVersion = (ipTypeAndLength & 0xf0) >> 4; int ipVersion = (ipTypeAndLength & 0xf0) >> 4;
if (ipVersion != 4) { if (ipVersion != 4) {
return null; throw new ParseException("Invalid IP version %d", ipVersion);
} }
// System.out.println("ipType is " + ipType); // System.out.println("ipType is " + ipType);
@ -759,8 +781,9 @@ abstract class DhcpPacket {
ipSrc = readIpAddress(packet); ipSrc = readIpAddress(packet);
ipDst = readIpAddress(packet); ipDst = readIpAddress(packet);
if (ipProto != IP_TYPE_UDP) // UDP if (ipProto != IP_TYPE_UDP) {
return null; throw new ParseException("Protocol not UDP: %d", ipProto);
}
// Skip options. This cannot cause us to read beyond the end of the buffer because the // Skip options. This cannot cause us to read beyond the end of the buffer because the
// IPv4 header cannot be more than (0x0f * 4) = 60 bytes long, and that is less than // IPv4 header cannot be more than (0x0f * 4) = 60 bytes long, and that is less than
@ -776,13 +799,19 @@ abstract class DhcpPacket {
short udpLen = packet.getShort(); short udpLen = packet.getShort();
short udpChkSum = packet.getShort(); short udpChkSum = packet.getShort();
if ((udpSrcPort != DHCP_SERVER) && (udpSrcPort != DHCP_CLIENT)) // Only accept packets to or from the well-known client port (expressly permitting
// packets from ports other than the well-known server port; http://b/24687559), and
// server-to-server packets, e.g. for relays.
if (!isPacketToOrFromClient(udpSrcPort, udpDstPort) &&
!isPacketServerToServer(udpSrcPort, udpDstPort)) {
return null; return null;
}
} }
// 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) {
return null; throw new ParseException("Invalid type or BOOTP packet too short, %d < %d",
packet.remaining(), MIN_PACKET_LENGTH_BOOTP);
} }
byte type = packet.get(); byte type = packet.get();
@ -805,7 +834,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) {
return null; throw new ParseException("Invalid IPv4 address: %s", Arrays.toString(ipv4addr));
} }
// Some DHCP servers have been known to announce invalid client hardware address values such // Some DHCP servers have been known to announce invalid client hardware address values such
@ -828,8 +857,10 @@ abstract class DhcpPacket {
int dhcpMagicCookie = packet.getInt(); int dhcpMagicCookie = packet.getInt();
if (dhcpMagicCookie != 0x63825363) if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) {
return null; throw new ParseException("Bad magic cookie 0x%08x, should be 0x%08x", dhcpMagicCookie,
DHCP_MAGIC_COOKIE);
}
// parse options // parse options
boolean notFinishedOptions = true; boolean notFinishedOptions = true;
@ -852,8 +883,9 @@ abstract class DhcpPacket {
expectedLen = 4; expectedLen = 4;
break; break;
case DHCP_ROUTER: case DHCP_ROUTER:
gateway = readIpAddress(packet); for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
expectedLen = 4; gateways.add(readIpAddress(packet));
}
break; break;
case DHCP_DNS_SERVER: case DHCP_DNS_SERVER:
for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) { for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
@ -937,18 +969,20 @@ abstract class DhcpPacket {
} }
if (expectedLen != optionLen) { if (expectedLen != optionLen) {
return null; throw new ParseException("Invalid length %d for option %d, expected %d",
optionLen, optionType, expectedLen);
} }
} }
} catch (BufferUnderflowException e) { } catch (BufferUnderflowException e) {
return null; throw new ParseException("BufferUnderflowException");
} }
} }
DhcpPacket newPacket; DhcpPacket newPacket;
switch(dhcpType) { switch(dhcpType) {
case -1: return null; case (byte) 0xFF:
throw new ParseException("No DHCP message type option");
case DHCP_MESSAGE_TYPE_DISCOVER: case DHCP_MESSAGE_TYPE_DISCOVER:
newPacket = new DhcpDiscoverPacket( newPacket = new DhcpDiscoverPacket(
transactionId, secs, clientMac, broadcast); transactionId, secs, clientMac, broadcast);
@ -981,14 +1015,13 @@ abstract class DhcpPacket {
clientMac); clientMac);
break; break;
default: default:
System.out.println("Unimplemented type: " + dhcpType); throw new ParseException("Unimplemented DHCP type %d", dhcpType);
return null;
} }
newPacket.mBroadcastAddress = bcAddr; newPacket.mBroadcastAddress = bcAddr;
newPacket.mDnsServers = dnsServers; newPacket.mDnsServers = dnsServers;
newPacket.mDomainName = domainName; newPacket.mDomainName = domainName;
newPacket.mGateway = gateway; newPacket.mGateways = gateways;
newPacket.mHostName = hostName; newPacket.mHostName = hostName;
newPacket.mLeaseTime = leaseTime; newPacket.mLeaseTime = leaseTime;
newPacket.mMessage = message; newPacket.mMessage = message;
@ -1009,7 +1042,7 @@ abstract class DhcpPacket {
* Parse a packet from an array of bytes, stopping at the given length. * Parse a packet from an array of bytes, stopping at the given length.
*/ */
public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType) public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType)
{ throws ParseException {
ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN); ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN);
return decodeFullPacket(buffer, pktType); return decodeFullPacket(buffer, pktType);
} }
@ -1044,7 +1077,11 @@ abstract class DhcpPacket {
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return null; return null;
} }
results.gateway = mGateway;
if (mGateways.size() > 0) {
results.gateway = mGateways.get(0);
}
results.dnsServers.addAll(mDnsServers); results.dnsServers.addAll(mDnsServers);
results.domains = mDomainName; results.domains = mDomainName;
results.serverAddress = mServerIdentifier; results.serverAddress = mServerIdentifier;
@ -1086,11 +1123,11 @@ abstract class DhcpPacket {
public static ByteBuffer buildOfferPacket(int encap, int transactionId, public static ByteBuffer buildOfferPacket(int encap, int transactionId,
boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr, boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr,
byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr,
Inet4Address gateway, List<Inet4Address> dnsServers, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
Inet4Address dhcpServerIdentifier, String domainName) { Inet4Address dhcpServerIdentifier, String domainName) {
DhcpPacket pkt = new DhcpOfferPacket( DhcpPacket pkt = new DhcpOfferPacket(
transactionId, (short) 0, broadcast, serverIpAddr, INADDR_ANY, clientIpAddr, mac); transactionId, (short) 0, broadcast, serverIpAddr, INADDR_ANY, clientIpAddr, mac);
pkt.mGateway = gateway; pkt.mGateways = gateways;
pkt.mDnsServers = dnsServers; pkt.mDnsServers = dnsServers;
pkt.mLeaseTime = timeout; pkt.mLeaseTime = timeout;
pkt.mDomainName = domainName; pkt.mDomainName = domainName;
@ -1106,11 +1143,11 @@ abstract class DhcpPacket {
public static ByteBuffer buildAckPacket(int encap, int transactionId, public static ByteBuffer buildAckPacket(int encap, int transactionId,
boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr, boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr,
byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr,
Inet4Address gateway, List<Inet4Address> dnsServers, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
Inet4Address dhcpServerIdentifier, String domainName) { Inet4Address dhcpServerIdentifier, String domainName) {
DhcpPacket pkt = new DhcpAckPacket( DhcpPacket pkt = new DhcpAckPacket(
transactionId, (short) 0, broadcast, serverIpAddr, INADDR_ANY, clientIpAddr, mac); transactionId, (short) 0, broadcast, serverIpAddr, INADDR_ANY, clientIpAddr, mac);
pkt.mGateway = gateway; pkt.mGateways = gateways;
pkt.mDnsServers = dnsServers; pkt.mDnsServers = dnsServers;
pkt.mLeaseTime = timeout; pkt.mLeaseTime = timeout;
pkt.mDomainName = domainName; pkt.mDomainName = domainName;

View File

@ -117,7 +117,7 @@ public class DhcpPacketTest extends TestCase {
private void assertDomainAndVendorInfoParses( private void assertDomainAndVendorInfoParses(
String expectedDomain, byte[] domainBytes, String expectedDomain, byte[] domainBytes,
String expectedVendorInfo, byte[] vendorInfoBytes) { String expectedVendorInfo, byte[] vendorInfoBytes) throws Exception {
ByteBuffer packet = new TestDhcpPacket(DHCP_MESSAGE_TYPE_OFFER) ByteBuffer packet = new TestDhcpPacket(DHCP_MESSAGE_TYPE_OFFER)
.setDomainBytes(domainBytes) .setDomainBytes(domainBytes)
.setVendorInfoBytes(vendorInfoBytes) .setVendorInfoBytes(vendorInfoBytes)
@ -158,17 +158,25 @@ public class DhcpPacketTest extends TestCase {
} }
private void assertLeaseTimeParses(boolean expectValid, Integer rawLeaseTime, private void assertLeaseTimeParses(boolean expectValid, Integer rawLeaseTime,
long leaseTimeMillis, byte[] leaseTimeBytes) { long leaseTimeMillis, byte[] leaseTimeBytes) throws Exception {
TestDhcpPacket testPacket = new TestDhcpPacket(DHCP_MESSAGE_TYPE_OFFER); TestDhcpPacket testPacket = new TestDhcpPacket(DHCP_MESSAGE_TYPE_OFFER);
if (leaseTimeBytes != null) { if (leaseTimeBytes != null) {
testPacket.setLeaseTimeBytes(leaseTimeBytes); testPacket.setLeaseTimeBytes(leaseTimeBytes);
} }
ByteBuffer packet = testPacket.build(); ByteBuffer packet = testPacket.build();
DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP); DhcpPacket offerPacket = null;
if (!expectValid) { if (!expectValid) {
assertNull(offerPacket); try {
offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
fail("Invalid packet parsed successfully: " + offerPacket);
} catch (ParseException expected) {
}
return; return;
} }
offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
assertNotNull(offerPacket);
assertEquals(rawLeaseTime, offerPacket.mLeaseTime); assertEquals(rawLeaseTime, offerPacket.mLeaseTime);
DhcpResults dhcpResults = offerPacket.toDhcpResults(); // Just check this doesn't crash. DhcpResults dhcpResults = offerPacket.toDhcpResults(); // Just check this doesn't crash.
assertEquals(leaseTimeMillis, offerPacket.getLeaseTimeMillis()); assertEquals(leaseTimeMillis, offerPacket.getLeaseTimeMillis());
@ -200,14 +208,14 @@ public class DhcpPacketTest extends TestCase {
} }
private void checkIpAddress(String expected, Inet4Address clientIp, Inet4Address yourIp, private void checkIpAddress(String expected, Inet4Address clientIp, Inet4Address yourIp,
byte[] netmaskBytes) { byte[] netmaskBytes) throws Exception {
checkIpAddress(expected, DHCP_MESSAGE_TYPE_OFFER, clientIp, yourIp, netmaskBytes); checkIpAddress(expected, DHCP_MESSAGE_TYPE_OFFER, clientIp, yourIp, netmaskBytes);
checkIpAddress(expected, DHCP_MESSAGE_TYPE_ACK, clientIp, yourIp, netmaskBytes); checkIpAddress(expected, DHCP_MESSAGE_TYPE_ACK, clientIp, yourIp, netmaskBytes);
} }
private void checkIpAddress(String expected, byte type, private void checkIpAddress(String expected, byte type,
Inet4Address clientIp, Inet4Address yourIp, Inet4Address clientIp, Inet4Address yourIp,
byte[] netmaskBytes) { byte[] netmaskBytes) throws Exception {
ByteBuffer packet = new TestDhcpPacket(type, clientIp, yourIp) ByteBuffer packet = new TestDhcpPacket(type, clientIp, yourIp)
.setNetmaskBytes(netmaskBytes) .setNetmaskBytes(netmaskBytes)
.build(); .build();
@ -506,4 +514,74 @@ public class DhcpPacketTest extends TestCase {
assertDhcpResults("10.32.158.205/20", "10.32.144.1", "148.88.65.52,148.88.65.53", assertDhcpResults("10.32.158.205/20", "10.32.144.1", "148.88.65.52,148.88.65.53",
"lancs.ac.uk", "10.32.255.128", null, 7200, false, dhcpResults); "lancs.ac.uk", "10.32.255.128", null, 7200, false, dhcpResults);
} }
@SmallTest
public void testUdpServerAnySourcePort() throws Exception {
final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
// Ethernet header.
"9cd917000000001c2e0000000800" +
// IP header.
"45a00148000040003d115087d18194fb0a0f7af2" +
// UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
// NOTE: The server source port is not the canonical port 67.
"C29F004401341268" +
// BOOTP header.
"02010600d628ba8200000000000000000a0f7af2000000000a0fc818" +
// MAC address.
"9cd91700000000000000000000000000" +
// Server name.
"0000000000000000000000000000000000000000000000000000000000000000" +
"0000000000000000000000000000000000000000000000000000000000000000" +
// File.
"0000000000000000000000000000000000000000000000000000000000000000" +
"0000000000000000000000000000000000000000000000000000000000000000" +
"0000000000000000000000000000000000000000000000000000000000000000" +
"0000000000000000000000000000000000000000000000000000000000000000" +
// Options.
"6382536335010236040a0169fc3304000151800104ffff000003040a0fc817060cd1818003d1819403" +
"d18180060f0777766d2e6564751c040a0fffffff000000"
).toCharArray(), false));
DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
assertTrue(offerPacket instanceof DhcpOfferPacket);
assertEquals("9CD917000000", HexDump.toHexString(offerPacket.getClientMac()));
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("10.15.122.242/16", "10.15.200.23",
"209.129.128.3,209.129.148.3,209.129.128.6",
"wvm.edu", "10.1.105.252", null, 86400, false, dhcpResults);
}
@SmallTest
public void testMultipleRouters() throws Exception {
final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
// Ethernet header.
"fc3d93000000" + "081735000000" + "0800" +
// IP header.
"45000148c2370000ff117ac2c0a8bd02ffffffff" +
// UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
"0043004401343beb" +
// BOOTP header.
"0201060027f518e20000800000000000c0a8bd310000000000000000" +
// MAC address.
"fc3d9300000000000000000000000000" +
// Server name.
"0000000000000000000000000000000000000000000000000000000000000000" +
"0000000000000000000000000000000000000000000000000000000000000000" +
// File.
"0000000000000000000000000000000000000000000000000000000000000000" +
"0000000000000000000000000000000000000000000000000000000000000000" +
"0000000000000000000000000000000000000000000000000000000000000000" +
"0000000000000000000000000000000000000000000000000000000000000000" +
// Options.
"638253633501023604c0abbd023304000070803a04000038403b04000062700104ffffff00" +
"0308c0a8bd01ffffff0006080808080808080404ff000000000000"
).toCharArray(), false));
DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
assertTrue(offerPacket instanceof DhcpOfferPacket);
assertEquals("FC3D93000000", HexDump.toHexString(offerPacket.getClientMac()));
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("192.168.189.49/24", "192.168.189.1", "8.8.8.8,8.8.4.4",
null, "192.171.189.2", null, 28800, false, dhcpResults);
}
} }