diff options
author | 2018-09-21 12:57:53 +0900 | |
---|---|---|
committer | 2018-10-01 11:01:39 +0900 | |
commit | f90a92bb7b806864ec65da3a6c6f1970ea8da710 (patch) | |
tree | 05d68c88e593b1eef0d354cc24cdaf0525c53768 | |
parent | c457d8c95ac06f5a37a6a766f06005827a454a9e (diff) |
Send hostname and MTU options in DHCP ACK/OFFER
The hostname option is only sent when requested in the requested
parameters option. This matches current behavior.
Test: with aosp/763982, regression tests now all pass
atest FrameworksNetTest
Bug: b/109584964
Change-Id: I793173fa893750ddbe72be09f4c2d70e5b285837
-rw-r--r-- | services/net/java/android/net/dhcp/DhcpPacket.java | 37 | ||||
-rw-r--r-- | services/net/java/android/net/dhcp/DhcpServer.java | 23 | ||||
-rw-r--r-- | tests/net/java/android/net/dhcp/DhcpPacketTest.java | 37 | ||||
-rw-r--r-- | tests/net/java/android/net/dhcp/DhcpServerTest.java | 23 |
4 files changed, 102 insertions, 18 deletions
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java index 77a3e2102452..6ba7d94117b1 100644 --- a/services/net/java/android/net/dhcp/DhcpPacket.java +++ b/services/net/java/android/net/dhcp/DhcpPacket.java @@ -1,5 +1,8 @@ package android.net.dhcp; +import static android.net.util.NetworkConstants.IPV4_MAX_MTU; +import static android.net.util.NetworkConstants.IPV4_MIN_MTU; + import android.annotation.Nullable; import android.net.DhcpResults; import android.net.LinkAddress; @@ -381,6 +384,26 @@ public abstract class DhcpPacket { } /** + * Returns whether a parameter is included in the parameter request list option of this packet. + * + * <p>If there is no parameter request list option in the packet, false is returned. + * + * @param paramId ID of the parameter, such as {@link #DHCP_MTU} or {@link #DHCP_HOST_NAME}. + */ + public boolean hasRequestedParam(byte paramId) { + if (mRequestedParams == null) { + return false; + } + + for (byte reqParam : mRequestedParams) { + if (reqParam == paramId) { + return true; + } + } + return false; + } + + /** * Creates a new L3 packet (including IP header) containing the * DHCP udp packet. This method relies upon the delegated method * finishPacket() to insert the per-packet contents. @@ -696,7 +719,11 @@ public abstract class DhcpPacket { addTlv(buf, DHCP_ROUTER, mGateways); addTlv(buf, DHCP_DNS_SERVER, mDnsServers); addTlv(buf, DHCP_DOMAIN_NAME, mDomainName); + addTlv(buf, DHCP_HOST_NAME, mHostName); addTlv(buf, DHCP_VENDOR_INFO, mVendorInfo); + if (mMtu != null && Short.toUnsignedInt(mMtu) >= IPV4_MIN_MTU) { + addTlv(buf, DHCP_MTU, mMtu); + } } /** @@ -1259,7 +1286,8 @@ public abstract class DhcpPacket { boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, - Inet4Address dhcpServerIdentifier, String domainName, boolean metered) { + Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, + short mtu) { DhcpPacket pkt = new DhcpOfferPacket( transactionId, (short) 0, broadcast, serverIpAddr, relayIp, INADDR_ANY /* clientIp */, yourIp, mac); @@ -1267,9 +1295,11 @@ public abstract class DhcpPacket { pkt.mDnsServers = dnsServers; pkt.mLeaseTime = timeout; pkt.mDomainName = domainName; + pkt.mHostName = hostname; pkt.mServerIdentifier = dhcpServerIdentifier; pkt.mSubnetMask = netMask; pkt.mBroadcastAddress = bcAddr; + pkt.mMtu = mtu; if (metered) { pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED; } @@ -1283,7 +1313,8 @@ public abstract class DhcpPacket { boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, - Inet4Address dhcpServerIdentifier, String domainName, boolean metered) { + Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, + short mtu) { DhcpPacket pkt = new DhcpAckPacket( transactionId, (short) 0, broadcast, serverIpAddr, relayIp, requestClientIp, yourIp, mac); @@ -1291,9 +1322,11 @@ public abstract class DhcpPacket { pkt.mDnsServers = dnsServers; pkt.mLeaseTime = timeout; pkt.mDomainName = domainName; + pkt.mHostName = hostname; pkt.mSubnetMask = netMask; pkt.mServerIdentifier = dhcpServerIdentifier; pkt.mBroadcastAddress = bcAddr; + pkt.mMtu = mtu; if (metered) { pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED; } diff --git a/services/net/java/android/net/dhcp/DhcpServer.java b/services/net/java/android/net/dhcp/DhcpServer.java index 2b3d577b0eae..cee6fa96bbc5 100644 --- a/services/net/java/android/net/dhcp/DhcpServer.java +++ b/services/net/java/android/net/dhcp/DhcpServer.java @@ -20,6 +20,7 @@ import static android.net.NetworkUtils.getBroadcastAddress; import static android.net.NetworkUtils.getPrefixMaskAsInet4Address; import static android.net.TrafficStats.TAG_SYSTEM_DHCP_SERVER; import static android.net.dhcp.DhcpPacket.DHCP_CLIENT; +import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME; import static android.net.dhcp.DhcpPacket.DHCP_SERVER; import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP; import static android.net.dhcp.DhcpPacket.INFINITE_LEASE; @@ -46,6 +47,7 @@ import android.os.Message; import android.os.SystemClock; import android.system.ErrnoException; import android.system.Os; +import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.HexDump; @@ -350,6 +352,19 @@ public class DhcpServer { return isEmpty(request.mClientIp) && (request.mBroadcast || isEmpty(lease.getNetAddr())); } + /** + * Get the hostname from a lease if non-empty and requested in the incoming request. + * @param request The incoming request. + * @return The hostname, or null if not requested or empty. + */ + @Nullable + private static String getHostnameIfRequested(@NonNull DhcpPacket request, + @NonNull DhcpLease lease) { + return request.hasRequestedParam(DHCP_HOST_NAME) && !TextUtils.isEmpty(lease.getHostname()) + ? lease.getHostname() + : null; + } + private boolean transmitOffer(@NonNull DhcpPacket request, @NonNull DhcpLease lease, @NonNull MacAddress clientMac) { final boolean broadcastFlag = getBroadcastFlag(request, lease); @@ -358,12 +373,14 @@ public class DhcpServer { getPrefixMaskAsInet4Address(mServingParams.serverAddr.getPrefixLength()); final Inet4Address broadcastAddr = getBroadcastAddress( mServingParams.getServerInet4Addr(), mServingParams.serverAddr.getPrefixLength()); + final String hostname = getHostnameIfRequested(request, lease); final ByteBuffer offerPacket = DhcpPacket.buildOfferPacket( ENCAP_BOOTP, request.mTransId, broadcastFlag, mServingParams.getServerInet4Addr(), request.mRelayIp, lease.getNetAddr(), request.mClientMac, timeout, prefixMask, broadcastAddr, new ArrayList<>(mServingParams.defaultRouters), new ArrayList<>(mServingParams.dnsServers), - mServingParams.getServerInet4Addr(), null /* domainName */, mServingParams.metered); + mServingParams.getServerInet4Addr(), null /* domainName */, hostname, + mServingParams.metered, (short) mServingParams.linkMtu); return transmitOfferOrAckPacket(offerPacket, request, lease, clientMac, broadcastFlag); } @@ -374,13 +391,15 @@ public class DhcpServer { // transmitOffer above final boolean broadcastFlag = getBroadcastFlag(request, lease); final int timeout = getLeaseTimeout(lease); + final String hostname = getHostnameIfRequested(request, lease); final ByteBuffer ackPacket = DhcpPacket.buildAckPacket(ENCAP_BOOTP, request.mTransId, broadcastFlag, mServingParams.getServerInet4Addr(), request.mRelayIp, lease.getNetAddr(), request.mClientIp, request.mClientMac, timeout, mServingParams.getPrefixMaskAsAddress(), mServingParams.getBroadcastAddress(), new ArrayList<>(mServingParams.defaultRouters), new ArrayList<>(mServingParams.dnsServers), - mServingParams.getServerInet4Addr(), null /* domainName */, mServingParams.metered); + mServingParams.getServerInet4Addr(), null /* domainName */, hostname, + mServingParams.metered, (short) mServingParams.linkMtu); return transmitOfferOrAckPacket(ackPacket, request, lease, clientMac, broadcastFlag); } diff --git a/tests/net/java/android/net/dhcp/DhcpPacketTest.java b/tests/net/java/android/net/dhcp/DhcpPacketTest.java index 312b3d1878d6..a592809618e6 100644 --- a/tests/net/java/android/net/dhcp/DhcpPacketTest.java +++ b/tests/net/java/android/net/dhcp/DhcpPacketTest.java @@ -25,6 +25,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.annotation.Nullable; import android.net.DhcpResults; import android.net.LinkAddress; import android.net.NetworkUtils; @@ -37,6 +38,7 @@ import com.android.internal.util.HexDump; import java.io.ByteArrayOutputStream; import java.net.Inet4Address; import java.nio.ByteBuffer; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -56,6 +58,8 @@ public class DhcpPacketTest { private static final Inet4Address NETMASK = getPrefixMaskAsInet4Address(PREFIX_LENGTH); private static final Inet4Address BROADCAST_ADDR = getBroadcastAddress( SERVER_ADDR, PREFIX_LENGTH); + private static final String HOSTNAME = "testhostname"; + private static final short MTU = 1500; // Use our own empty address instead of Inet4Address.ANY or INADDR_ANY to ensure that the code // doesn't use == instead of equals when comparing addresses. private static final Inet4Address ANY = (Inet4Address) v4Address("0.0.0.0"); @@ -960,7 +964,8 @@ public class DhcpPacketTest { assertTrue(msg, Arrays.equals(expected, actual)); } - public void checkBuildOfferPacket(int leaseTimeSecs) throws Exception { + public void checkBuildOfferPacket(int leaseTimeSecs, @Nullable String hostname) + throws Exception { final int renewalTime = (int) (Integer.toUnsignedLong(leaseTimeSecs) / 2); final int rebindingTime = (int) (Integer.toUnsignedLong(leaseTimeSecs) * 875 / 1000); final int transactionId = 0xdeadbeef; @@ -971,7 +976,8 @@ public class DhcpPacketTest { CLIENT_MAC, leaseTimeSecs, NETMASK /* netMask */, BROADCAST_ADDR /* bcAddr */, Collections.singletonList(SERVER_ADDR) /* gateways */, Collections.singletonList(SERVER_ADDR) /* dnsServers */, - SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, false /* metered */); + SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, hostname, + false /* metered */, MTU); ByteArrayOutputStream bos = new ByteArrayOutputStream(); // BOOTP headers @@ -1027,12 +1033,22 @@ public class DhcpPacketTest { // Nameserver bos.write(new byte[] { (byte) 0x06, (byte) 0x04 }); bos.write(SERVER_ADDR.getAddress()); + // Hostname + if (hostname != null) { + bos.write(new byte[]{(byte) 0x0c, (byte) hostname.length()}); + bos.write(hostname.getBytes(Charset.forName("US-ASCII"))); + } + // MTU + bos.write(new byte[] { (byte) 0x1a, (byte) 0x02 }); + bos.write(shortToByteArray(MTU)); // End options. bos.write(0xff); - final byte[] expected = bos.toByteArray(); - assertTrue((expected.length & 1) == 0); + if ((bos.size() & 1) != 0) { + bos.write(0x00); + } + final byte[] expected = bos.toByteArray(); final byte[] actual = new byte[packet.limit()]; packet.get(actual); final String msg = "Expected:\n " + HexDump.dumpHexString(expected) + @@ -1042,13 +1058,18 @@ public class DhcpPacketTest { @Test public void testOfferPacket() throws Exception { - checkBuildOfferPacket(3600); - checkBuildOfferPacket(Integer.MAX_VALUE); - checkBuildOfferPacket(0x80000000); - checkBuildOfferPacket(INFINITE_LEASE); + checkBuildOfferPacket(3600, HOSTNAME); + checkBuildOfferPacket(Integer.MAX_VALUE, HOSTNAME); + checkBuildOfferPacket(0x80000000, HOSTNAME); + checkBuildOfferPacket(INFINITE_LEASE, HOSTNAME); + checkBuildOfferPacket(3600, null); } private static byte[] intToByteArray(int val) { return ByteBuffer.allocate(4).putInt(val).array(); } + + private static byte[] shortToByteArray(short val) { + return ByteBuffer.allocate(2).putShort(val).array(); + } } diff --git a/tests/net/java/android/net/dhcp/DhcpServerTest.java b/tests/net/java/android/net/dhcp/DhcpServerTest.java index 45a50d9a8b5f..df34c7310b63 100644 --- a/tests/net/java/android/net/dhcp/DhcpServerTest.java +++ b/tests/net/java/android/net/dhcp/DhcpServerTest.java @@ -17,6 +17,7 @@ package android.net.dhcp; import static android.net.dhcp.DhcpPacket.DHCP_CLIENT; +import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME; import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP; import static android.net.dhcp.DhcpPacket.INADDR_ANY; import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST; @@ -87,6 +88,7 @@ public class DhcpServerTest { Arrays.asList(parseAddr("192.168.0.200"), parseAddr("192.168.0.201"))); private static final long TEST_LEASE_TIME_SECS = 3600L; private static final int TEST_MTU = 1500; + private static final String TEST_HOSTNAME = "testhostname"; private static final int TEST_TRANSACTION_ID = 123; private static final byte[] TEST_CLIENT_MAC_BYTES = new byte [] { 1, 2, 3, 4, 5, 6 }; @@ -96,7 +98,10 @@ public class DhcpServerTest { private static final long TEST_CLOCK_TIME = 1234L; private static final int TEST_LEASE_EXPTIME_SECS = 3600; private static final DhcpLease TEST_LEASE = new DhcpLease(null, TEST_CLIENT_MAC, - TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS*1000L + TEST_CLOCK_TIME, null /* hostname */); + TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME, + null /* hostname */); + private static final DhcpLease TEST_LEASE_WITH_HOSTNAME = new DhcpLease(null, TEST_CLIENT_MAC, + TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME, TEST_HOSTNAME); @NonNull @Mock private Dependencies mDeps; @@ -217,15 +222,17 @@ public class DhcpServerTest { public void testRequest_Selecting_Ack() throws Exception { when(mRepository.requestLease(isNull() /* clientId */, eq(TEST_CLIENT_MAC), eq(INADDR_ANY) /* clientAddr */, eq(INADDR_ANY) /* relayAddr */, - eq(TEST_CLIENT_ADDR) /* reqAddr */, eq(true) /* sidSet */, isNull() /* hostname */)) - .thenReturn(TEST_LEASE); + eq(TEST_CLIENT_ADDR) /* reqAddr */, eq(true) /* sidSet */, eq(TEST_HOSTNAME))) + .thenReturn(TEST_LEASE_WITH_HOSTNAME); final DhcpRequestPacket request = makeRequestSelectingPacket(); + request.mHostName = TEST_HOSTNAME; + request.mRequestedParams = new byte[] { DHCP_HOST_NAME }; mServer.processPacket(request, DHCP_CLIENT); assertResponseSentTo(TEST_CLIENT_ADDR); final DhcpAckPacket packet = assertAck(getPacket()); - assertMatchesTestLease(packet); + assertMatchesTestLease(packet, TEST_HOSTNAME); } @Test @@ -270,14 +277,18 @@ public class DhcpServerTest { * - other request states (init-reboot/renewing/rebinding) */ - private void assertMatchesTestLease(@NonNull DhcpPacket packet) { + private void assertMatchesTestLease(@NonNull DhcpPacket packet, @Nullable String hostname) { assertMatchesClient(packet); assertFalse(packet.hasExplicitClientId()); assertEquals(TEST_SERVER_ADDR, packet.mServerIdentifier); assertEquals(TEST_CLIENT_ADDR, packet.mYourIp); assertNotNull(packet.mLeaseTime); assertEquals(TEST_LEASE_EXPTIME_SECS, (int) packet.mLeaseTime); - assertNull(packet.mHostName); + assertEquals(hostname, packet.mHostName); + } + + private void assertMatchesTestLease(@NonNull DhcpPacket packet) { + assertMatchesTestLease(packet, null); } private void assertMatchesClient(@NonNull DhcpPacket packet) { |