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

Commit a420b57a authored by Remi NGUYEN VAN's avatar Remi NGUYEN VAN
Browse files

Add DhcpServingParams

Those parameters will be used to start DhcpServer or update its
configuration.

Test: runtest DhcpServingParamsTest.java
Bug: b/109584964
Change-Id: Id8d3dcf62d66dcb02accffa8d8500e30f07af452
parent 1885805a
Loading
Loading
Loading
Loading
+25 −3
Original line number Diff line number Diff line
@@ -161,7 +161,7 @@ public class NetworkUtils {
     * @param hostAddress an int coding for an IPv4 address, where higher-order int byte is
     *                    lower-order IPv4 address byte
     */
    public static InetAddress intToInet4AddressHTL(int hostAddress) {
    public static Inet4Address intToInet4AddressHTL(int hostAddress) {
        return intToInet4AddressHTH(Integer.reverseBytes(hostAddress));
    }

@@ -169,14 +169,14 @@ public class NetworkUtils {
     * Convert a IPv4 address from an integer to an InetAddress (0x01020304 -> 1.2.3.4)
     * @param hostAddress an int coding for an IPv4 address
     */
    public static InetAddress intToInet4AddressHTH(int hostAddress) {
    public static Inet4Address intToInet4AddressHTH(int hostAddress) {
        byte[] addressBytes = { (byte) (0xff & (hostAddress >> 24)),
                (byte) (0xff & (hostAddress >> 16)),
                (byte) (0xff & (hostAddress >> 8)),
                (byte) (0xff & hostAddress) };

        try {
            return InetAddress.getByAddress(addressBytes);
            return (Inet4Address) InetAddress.getByAddress(addressBytes);
        } catch (UnknownHostException e) {
            throw new AssertionError();
        }
@@ -408,6 +408,28 @@ public class NetworkUtils {
        return new Pair<InetAddress, Integer>(address, prefixLength);
    }

    /**
     * Get a prefix mask as Inet4Address for a given prefix length.
     *
     * <p>For example 20 -> 255.255.240.0
     */
    public static Inet4Address getPrefixMaskAsInet4Address(int prefixLength)
            throws IllegalArgumentException {
        return intToInet4AddressHTH(prefixLengthToV4NetmaskIntHTH(prefixLength));
    }

    /**
     * Get the broadcast address for a given prefix.
     *
     * <p>For example 192.168.0.1/24 -> 192.168.0.255
     */
    public static Inet4Address getBroadcastAddress(Inet4Address addr, int prefixLength)
            throws IllegalArgumentException {
        final int intBroadcastAddr = inet4AddressToIntHTH(addr)
                | ~prefixLengthToV4NetmaskIntHTH(prefixLength);
        return intToInet4AddressHTH(intBroadcastAddr);
    }

    /**
     * Check if IP address type is consistent between two InetAddress.
     * @return true if both are the same type.  False otherwise.
+1 −1
Original line number Diff line number Diff line
@@ -512,7 +512,7 @@ class DhcpLeaseRepository {
        // Loop until a free address is found, or there are no more addresses.
        // There is slightly less than this many usable addresses, but some extra looping is OK
        for (int i = 0; i < mNumAddresses; i++) {
            final Inet4Address addr = (Inet4Address) intToInet4AddressHTH(intAddr);
            final Inet4Address addr = intToInet4AddressHTH(intAddr);
            if (isAvailable(addr) && !mDeclinedAddrs.containsKey(addr)) {
                return new DhcpLease(clientId, hwAddr, addr, expTime, hostname);
            }
+262 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.dhcp;

import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
import static android.net.dhcp.DhcpPacket.INFINITE_LEASE;
import static android.net.util.NetworkConstants.IPV4_MAX_MTU;
import static android.net.util.NetworkConstants.IPV4_MIN_MTU;

import static java.lang.Integer.toUnsignedLong;

import android.annotation.NonNull;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.NetworkUtils;

import java.net.Inet4Address;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * Parameters used by the DhcpServer to serve requests.
 *
 * <p>Instances are immutable. Use {@link DhcpServingParams.Builder} to instantiate.
 * @hide
 */
public class DhcpServingParams {
    public static final int MTU_UNSET = 0;
    public static final int MIN_PREFIX_LENGTH = 16;
    public static final int MAX_PREFIX_LENGTH = 30;

    /** Server inet address and prefix to serve */
    @NonNull
    public final LinkAddress serverAddr;

    /**
     * Default routers to be advertised to DHCP clients. May be empty.
     * This set is provided by {@link DhcpServingParams.Builder} and is immutable.
     */
    @NonNull
    public final Set<Inet4Address> defaultRouters;

    /**
     * DNS servers to be advertised to DHCP clients. May be empty.
     * This set is provided by {@link DhcpServingParams.Builder} and is immutable.
     */
    @NonNull
    public final Set<Inet4Address> dnsServers;

    /**
     * Excluded addresses that the DHCP server is not allowed to assign to clients.
     * This set is provided by {@link DhcpServingParams.Builder} and is immutable.
     */
    @NonNull
    public final Set<Inet4Address> excludedAddrs;

    // DHCP uses uint32. Use long for clearer code, and check range when building.
    public final long dhcpLeaseTimeSecs;
    public final int linkMtu;

    /**
     * Checked exception thrown when some parameters used to build {@link DhcpServingParams} are
     * missing or invalid.
     */
    public static class InvalidParameterException extends Exception {
        public InvalidParameterException(String message) {
            super(message);
        }
    }

    private DhcpServingParams(@NonNull LinkAddress serverAddr,
            @NonNull Set<Inet4Address> defaultRouters,
            @NonNull Set<Inet4Address> dnsServers, @NonNull Set<Inet4Address> excludedAddrs,
            long dhcpLeaseTimeSecs, int linkMtu) {
        this.serverAddr = serverAddr;
        this.defaultRouters = defaultRouters;
        this.dnsServers = dnsServers;
        this.excludedAddrs = excludedAddrs;
        this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
        this.linkMtu = linkMtu;
    }

    @NonNull
    public Inet4Address getServerInet4Addr() {
        return (Inet4Address) serverAddr.getAddress();
    }

    /**
     * Get the served prefix mask as an IPv4 address.
     *
     * <p>For example, if the served prefix is 192.168.42.0/24, this will return 255.255.255.0.
     */
    @NonNull
    public Inet4Address getPrefixMaskAsAddress() {
        return getPrefixMaskAsInet4Address(serverAddr.getPrefixLength());
    }

    /**
     * Get the server broadcast address.
     *
     * <p>For example, if the server {@link LinkAddress} is 192.168.42.1/24, this will return
     * 192.168.42.255.
     */
    @NonNull
    public Inet4Address getBroadcastAddress() {
        return NetworkUtils.getBroadcastAddress(getServerInet4Addr(), serverAddr.getPrefixLength());
    }

    /**
     * Utility class to create new instances of {@link DhcpServingParams} while checking validity
     * of the parameters.
     */
    public static class Builder {
        private LinkAddress serverAddr;
        private Set<Inet4Address> defaultRouters;
        private Set<Inet4Address> dnsServers;
        private Set<Inet4Address> excludedAddrs;
        private long dhcpLeaseTimeSecs;
        private int linkMtu = MTU_UNSET;

        /**
         * Set the server address and served prefix for the DHCP server.
         *
         * <p>This parameter is required.
         */
        public Builder setServerAddr(@NonNull LinkAddress serverAddr) {
            this.serverAddr = serverAddr;
            return this;
        }

        /**
         * Set the default routers to be advertised to DHCP clients.
         *
         * <p>Each router must be inside the served prefix. This may be an empty set, but it must
         * always be set explicitly before building the {@link DhcpServingParams}.
         */
        public Builder setDefaultRouters(@NonNull Set<Inet4Address> defaultRouters) {
            this.defaultRouters = defaultRouters;
            return this;
        }

        /**
         * Set the DNS servers to be advertised to DHCP clients.
         *
         * <p>This may be an empty set, but it must always be set explicitly before building the
         * {@link DhcpServingParams}.
         */
        public Builder setDnsServers(@NonNull Set<Inet4Address> dnsServers) {
            this.dnsServers = dnsServers;
            return this;
        }

        /**
         * Set excluded addresses that the DHCP server is not allowed to assign to clients.
         *
         * <p>This parameter is optional. DNS servers and default routers are always excluded
         * and do not need to be set here.
         */
        public Builder setExcludedAddrs(@NonNull Set<Inet4Address> excludedAddrs) {
            this.excludedAddrs = excludedAddrs;
            return this;
        }

        /**
         * Set the lease time for leases assigned by the DHCP server.
         *
         * <p>This parameter is required.
         */
        public Builder setDhcpLeaseTimeSecs(long dhcpLeaseTimeSecs) {
            this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
            return this;
        }

        /**
         * Set the link MTU to be advertised to DHCP clients.
         *
         * <p>If set to {@link #MTU_UNSET}, no MTU will be advertised to clients. This parameter
         * is optional and defaults to {@link #MTU_UNSET}.
         */
        public Builder setLinkMtu(int linkMtu) {
            this.linkMtu = linkMtu;
            return this;
        }

        /**
         * Create a new {@link DhcpServingParams} instance based on parameters set in the builder.
         *
         * <p>This method has no side-effects. If it does not throw, a valid
         * {@link DhcpServingParams} is returned.
         * @return The constructed parameters.
         * @throws InvalidParameterException At least one parameter is missing or invalid.
         */
        @NonNull
        public DhcpServingParams build() throws InvalidParameterException {
            if (serverAddr == null) {
                throw new InvalidParameterException("Missing serverAddr");
            }
            if (defaultRouters == null) {
                throw new InvalidParameterException("Missing defaultRouters");
            }
            if (dnsServers == null) {
                // Empty set is OK, but enforce explicitly setting it
                throw new InvalidParameterException("Missing dnsServers");
            }
            if (dhcpLeaseTimeSecs <= 0 || dhcpLeaseTimeSecs > toUnsignedLong(INFINITE_LEASE)) {
                throw new InvalidParameterException("Invalid lease time: " + dhcpLeaseTimeSecs);
            }
            if (linkMtu != MTU_UNSET && (linkMtu < IPV4_MIN_MTU || linkMtu > IPV4_MAX_MTU)) {
                throw new InvalidParameterException("Invalid link MTU: " + linkMtu);
            }
            if (!serverAddr.isIPv4()) {
                throw new InvalidParameterException("serverAddr must be IPv4");
            }
            if (serverAddr.getPrefixLength() < MIN_PREFIX_LENGTH
                    || serverAddr.getPrefixLength() > MAX_PREFIX_LENGTH) {
                throw new InvalidParameterException("Prefix length is not in supported range");
            }

            final IpPrefix prefix = makeIpPrefix(serverAddr);
            for (Inet4Address addr : defaultRouters) {
                if (!prefix.contains(addr)) {
                    throw new InvalidParameterException(String.format(
                            "Default router %s is not in server prefix %s", addr, serverAddr));
                }
            }

            final Set<Inet4Address> excl = new HashSet<>();
            if (excludedAddrs != null) {
                excl.addAll(excludedAddrs);
            }
            excl.add((Inet4Address) serverAddr.getAddress());
            excl.addAll(defaultRouters);
            excl.addAll(dnsServers);

            return new DhcpServingParams(serverAddr,
                    Collections.unmodifiableSet(new HashSet<>(defaultRouters)),
                    Collections.unmodifiableSet(new HashSet<>(dnsServers)),
                    Collections.unmodifiableSet(excl),
                    dhcpLeaseTimeSecs, linkMtu);
        }
    }

    @NonNull
    static IpPrefix makeIpPrefix(@NonNull LinkAddress addr) {
        return new IpPrefix(addr.getAddress(), addr.getPrefixLength());
    }
}
+3 −1
Original line number Diff line number Diff line
@@ -77,10 +77,12 @@ public final class NetworkConstants {
    /**
     * IPv4 constants.
     *
     * See als:
     * See also:
     *     - https://tools.ietf.org/html/rfc791
     */
    public static final int IPV4_HEADER_MIN_LEN = 20;
    public static final int IPV4_MIN_MTU = 68;
    public static final int IPV4_MAX_MTU = 65_535;
    public static final int IPV4_IHL_MASK = 0xf;
    public static final int IPV4_FLAGS_OFFSET = 6;
    public static final int IPV4_FRAGMENT_MASK = 0x1fff;
+42 −1
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ import static android.net.NetworkUtils.intToInet4AddressHTL;
import static android.net.NetworkUtils.netmaskToPrefixLength;
import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTH;
import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTL;
import static android.net.NetworkUtils.getBroadcastAddress;
import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;

import static junit.framework.Assert.assertEquals;

@@ -125,7 +127,6 @@ public class NetworkUtilsTest {
        assertInvalidNetworkMask(IPv4Address("255.255.0.255"));
    }


    @Test
    public void testPrefixLengthToV4NetmaskIntHTL() {
        assertEquals(0, prefixLengthToV4NetmaskIntHTL(0));
@@ -266,4 +267,44 @@ public class NetworkUtilsTest {
        assertEquals(BigInteger.valueOf(7l - 4 + 4 + 16 + 65536),
                NetworkUtils.routedIPv6AddressCount(set));
    }

    @Test
    public void testGetPrefixMaskAsAddress() {
        assertEquals("255.255.240.0", getPrefixMaskAsInet4Address(20).getHostAddress());
        assertEquals("255.0.0.0", getPrefixMaskAsInet4Address(8).getHostAddress());
        assertEquals("0.0.0.0", getPrefixMaskAsInet4Address(0).getHostAddress());
        assertEquals("255.255.255.255", getPrefixMaskAsInet4Address(32).getHostAddress());
    }

    @Test(expected = IllegalArgumentException.class)
    public void testGetPrefixMaskAsAddress_PrefixTooLarge() {
        getPrefixMaskAsInet4Address(33);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testGetPrefixMaskAsAddress_NegativePrefix() {
        getPrefixMaskAsInet4Address(-1);
    }

    @Test
    public void testGetBroadcastAddress() {
        assertEquals("192.168.15.255",
                getBroadcastAddress(IPv4Address("192.168.0.123"), 20).getHostAddress());
        assertEquals("192.255.255.255",
                getBroadcastAddress(IPv4Address("192.168.0.123"), 8).getHostAddress());
        assertEquals("192.168.0.123",
                getBroadcastAddress(IPv4Address("192.168.0.123"), 32).getHostAddress());
        assertEquals("255.255.255.255",
                getBroadcastAddress(IPv4Address("192.168.0.123"), 0).getHostAddress());
    }

    @Test(expected = IllegalArgumentException.class)
    public void testGetBroadcastAddress_PrefixTooLarge() {
        getBroadcastAddress(IPv4Address("192.168.0.123"), 33);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testGetBroadcastAddress_NegativePrefix() {
        getBroadcastAddress(IPv4Address("192.168.0.123"), -1);
    }
}
Loading