Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3b12359e authored by Remi NGUYEN VAN's avatar Remi NGUYEN VAN Committed by Gerrit Code Review
Browse files

Merge "Send hostname and MTU options in DHCP ACK/OFFER"

parents 5f7129b9 f90a92bb
Loading
Loading
Loading
Loading
+35 −2
Original line number Diff line number Diff line
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;
@@ -380,6 +383,26 @@ public abstract class DhcpPacket {
        return clientId;
    }

    /**
     * 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
@@ -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;
        }
+21 −2
Original line number Diff line number Diff line
@@ -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);
    }
+29 −8
Original line number Diff line number Diff line
@@ -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();
    }
}
+17 −6
Original line number Diff line number Diff line
@@ -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) {