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

Commit 1a0b100b authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 6101340 from 768f7ee0 to rvc-release

Change-Id: I7e3d0f22bff6200189156e1d1293271f162492b8
parents 11a4120b 768f7ee0
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -46,4 +46,7 @@
    <!-- Set to true if NetworkMonitor needs to load the resource by neighbor mcc when device
    <!-- Set to true if NetworkMonitor needs to load the resource by neighbor mcc when device
         doesn't have a SIM card inserted. -->
         doesn't have a SIM card inserted. -->
    <bool name="config_no_sim_card_uses_neighbor_mcc">false</bool>
    <bool name="config_no_sim_card_uses_neighbor_mcc">false</bool>

    <!-- Configuration for including DHCP client hostname option -->
    <bool name="config_dhcp_client_hostname">false</bool>
</resources>
</resources>
+10 −0
Original line number Original line Diff line number Diff line
@@ -24,6 +24,16 @@
            <item type="bool" name="config_no_sim_card_uses_neighbor_mcc"/>
            <item type="bool" name="config_no_sim_card_uses_neighbor_mcc"/>
            <!-- Configuration value for DhcpResults -->
            <!-- Configuration value for DhcpResults -->
            <item type="array" name="config_default_dns_servers"/>
            <item type="array" name="config_default_dns_servers"/>
            <!-- Configuration for including DHCP client hostname option.
            If this option is true, client hostname set in Settings.Global.DEVICE_NAME will be
            included in DHCPDISCOVER/DHCPREQUEST, otherwise, the DHCP hostname option will not
            be sent. RFC952 and RFC1123 stipulates an valid hostname should be only comprised of
            'a-z', 'A-Z' and '-', and the length should be up to 63 octets or less (RFC1035#2.3.4),
            platform will perform best-effort transliteration for other characters. Anything that
            could be used to identify the device uniquely is not recommended, e.g. user's name,
            random number and etc.
            -->
            <item type="bool" name="config_dhcp_client_hostname"/>
        </policy>
        </policy>
    </overlayable>
    </overlayable>
</resources>
</resources>
+88 −60
Original line number Original line Diff line number Diff line
@@ -68,6 +68,7 @@ import android.net.ipmemorystore.OnStatusListener;
import android.net.metrics.DhcpClientEvent;
import android.net.metrics.DhcpClientEvent;
import android.net.metrics.DhcpErrorEvent;
import android.net.metrics.DhcpErrorEvent;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.IpConnectivityLog;
import android.net.util.HostnameTransliterator;
import android.net.util.InterfaceParams;
import android.net.util.InterfaceParams;
import android.net.util.NetworkStackUtils;
import android.net.util.NetworkStackUtils;
import android.net.util.PacketReader;
import android.net.util.PacketReader;
@@ -76,6 +77,7 @@ import android.os.Handler;
import android.os.Message;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.SystemClock;
import android.provider.Settings;
import android.system.ErrnoException;
import android.system.ErrnoException;
import android.system.Os;
import android.system.Os;
import android.util.EventLog;
import android.util.EventLog;
@@ -154,34 +156,40 @@ public class DhcpClient extends StateMachine {
    // seconds to avoid excessive traffic, but it's too long).
    // seconds to avoid excessive traffic, but it's too long).
    @VisibleForTesting
    @VisibleForTesting
    public static final String DHCP_RESTART_CONFIG_DELAY = "dhcp_restart_configuration_delay";
    public static final String DHCP_RESTART_CONFIG_DELAY = "dhcp_restart_configuration_delay";
    private static final int DEFAULT_DHCP_RESTART_CONFIG_DELAY_SEC = 1 * SECONDS;
    private static final int DEFAULT_DHCP_RESTART_CONFIG_DELAY_MS = 1 * SECONDS;
    private static final int MAX_DHCP_CLIENT_RESTART_CONFIG_DELAY_MS = 10 * SECONDS;


    // Initial random delay before sending first ARP probe.
    // Initial random delay before sending first ARP probe.
    @VisibleForTesting
    @VisibleForTesting
    public static final String ARP_FIRST_PROBE_DELAY_MS = "arp_first_probe_delay";
    public static final String ARP_FIRST_PROBE_DELAY_MS = "arp_first_probe_delay";
    private static final int DEFAULT_ARP_FIRST_PROBE_DELAY_MS = 100;
    private static final int DEFAULT_ARP_FIRST_PROBE_DELAY_MS = 100;
    private static final int MAX_ARP_FIRST_PROBE_DELAY_MS = 1 * SECONDS;


    // Minimum delay until retransmitting the probe. The probe will be retransmitted after a
    // Minimum delay until retransmitting the probe. The probe will be retransmitted after a
    // random number of milliseconds in the range ARP_PROBE_MIN_MS and ARP_PROBE_MAX_MS.
    // random number of milliseconds in the range ARP_PROBE_MIN_MS and ARP_PROBE_MAX_MS.
    @VisibleForTesting
    @VisibleForTesting
    public static final String ARP_PROBE_MIN_MS = "arp_probe_min";
    public static final String ARP_PROBE_MIN_MS = "arp_probe_min";
    private static final int DEFAULT_ARP_PROBE_MIN_MS = 100;
    private static final int DEFAULT_ARP_PROBE_MIN_MS = 100;
    private static final int MAX_ARP_PROBE_MIN_MS = 1 * SECONDS;


    // Maximum delay until retransmitting the probe.
    // Maximum delay until retransmitting the probe.
    @VisibleForTesting
    @VisibleForTesting
    public static final String ARP_PROBE_MAX_MS = "arp_probe_max";
    public static final String ARP_PROBE_MAX_MS = "arp_probe_max";
    private static final int DEFAULT_ARP_PROBE_MAX_MS = 300;
    private static final int DEFAULT_ARP_PROBE_MAX_MS = 300;
    private static final int MAX_ARP_PROBE_MAX_MS = 2 * SECONDS;


    // Initial random delay before sending first ARP Announcement after completing Probe packet
    // Initial random delay before sending first ARP Announcement after completing Probe packet
    // transmission.
    // transmission.
    @VisibleForTesting
    @VisibleForTesting
    public static final String ARP_FIRST_ANNOUNCE_DELAY_MS = "arp_first_announce_delay";
    public static final String ARP_FIRST_ANNOUNCE_DELAY_MS = "arp_first_announce_delay";
    private static final int DEFAULT_ARP_FIRST_ANNOUNCE_DELAY_MS = 100;
    private static final int DEFAULT_ARP_FIRST_ANNOUNCE_DELAY_MS = 100;
    private static final int MAX_ARP_FIRST_ANNOUNCE_DELAY_MS = 2 * SECONDS;


    // Time between retransmitting ARP Announcement packets.
    // Time between retransmitting ARP Announcement packets.
    @VisibleForTesting
    @VisibleForTesting
    public static final String ARP_ANNOUNCE_INTERVAL_MS = "arp_announce_interval";
    public static final String ARP_ANNOUNCE_INTERVAL_MS = "arp_announce_interval";
    private static final int DEFAULT_ARP_ANNOUNCE_INTERVAL_MS = 100;
    private static final int DEFAULT_ARP_ANNOUNCE_INTERVAL_MS = 100;
    private static final int MAX_ARP_ANNOUNCE_INTERVAL_MS = 2 * SECONDS;


    // Max conflict count before configuring interface with declined IP address anyway.
    // Max conflict count before configuring interface with declined IP address anyway.
    private static final int MAX_CONFLICTS_COUNT = 2;
    private static final int MAX_CONFLICTS_COUNT = 2;
@@ -306,6 +314,8 @@ public class DhcpClient extends StateMachine {
    private final NetworkStackIpMemoryStore mIpMemoryStore;
    private final NetworkStackIpMemoryStore mIpMemoryStore;
    @Nullable
    @Nullable
    private DhcpPacketHandler mDhcpPacketHandler;
    private DhcpPacketHandler mDhcpPacketHandler;
    @Nullable
    private final String mHostname;


    // Milliseconds SystemClock timestamps used to record transition times to DhcpBoundState.
    // Milliseconds SystemClock timestamps used to record transition times to DhcpBoundState.
    private long mLastInitEnterTime;
    private long mLastInitEnterTime;
@@ -349,6 +359,22 @@ public class DhcpClient extends StateMachine {
            mNetworkStackIpMemoryStore = store;
            mNetworkStackIpMemoryStore = store;
        }
        }


        /**
         * Get the configuration from RRO to check whether or not to send hostname option in
         * DHCPDISCOVER/DHCPREQUEST message.
         */
        public boolean getSendHostnameOption(final Context context) {
            return context.getResources().getBoolean(R.bool.config_dhcp_client_hostname);
        }

        /**
         * Get the device name from system settings.
         */
        public String getDeviceName(final Context context) {
            return Settings.Global.getString(context.getContentResolver(),
                    Settings.Global.DEVICE_NAME);
        }

        /**
        /**
         * Get a IpMemoryStore instance.
         * Get a IpMemoryStore instance.
         */
         */
@@ -367,33 +393,10 @@ public class DhcpClient extends StateMachine {
        /**
        /**
         * Get the Integer value of relevant DeviceConfig properties of Connectivity namespace.
         * Get the Integer value of relevant DeviceConfig properties of Connectivity namespace.
         */
         */
        public int getIntDeviceConfig(final String name) {
        public int getIntDeviceConfig(final String name, int minimumValue, int maximumValue,
            final int defaultValue;
                int defaultValue) {
            switch (name) {
            return NetworkStackUtils.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
                case DHCP_RESTART_CONFIG_DELAY:
                    name, minimumValue, maximumValue, defaultValue);
                    defaultValue = DEFAULT_DHCP_RESTART_CONFIG_DELAY_SEC;
                    break;
                case ARP_FIRST_PROBE_DELAY_MS:
                    defaultValue = DEFAULT_ARP_FIRST_PROBE_DELAY_MS;
                    break;
                case ARP_PROBE_MIN_MS:
                    defaultValue = DEFAULT_ARP_PROBE_MIN_MS;
                    break;
                case ARP_PROBE_MAX_MS:
                    defaultValue = DEFAULT_ARP_PROBE_MAX_MS;
                    break;
                case ARP_FIRST_ANNOUNCE_DELAY_MS:
                    defaultValue = DEFAULT_ARP_FIRST_ANNOUNCE_DELAY_MS;
                    break;
                case ARP_ANNOUNCE_INTERVAL_MS:
                    defaultValue = DEFAULT_ARP_ANNOUNCE_INTERVAL_MS;
                    break;
                default:
                    Log.e(TAG, "Invalid experiment flag: " + name);
                    return 0;
            }
            return NetworkStackUtils.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY, name,
                    defaultValue);
        }
        }


        /**
        /**
@@ -450,6 +453,11 @@ public class DhcpClient extends StateMachine {
        mRenewAlarm = makeWakeupMessage("RENEW", CMD_RENEW_DHCP);
        mRenewAlarm = makeWakeupMessage("RENEW", CMD_RENEW_DHCP);
        mRebindAlarm = makeWakeupMessage("REBIND", CMD_REBIND_DHCP);
        mRebindAlarm = makeWakeupMessage("REBIND", CMD_REBIND_DHCP);
        mExpiryAlarm = makeWakeupMessage("EXPIRY", CMD_EXPIRE_DHCP);
        mExpiryAlarm = makeWakeupMessage("EXPIRY", CMD_EXPIRE_DHCP);

        // Transliterate hostname read from system settings if RRO option is enabled.
        final boolean sendHostname = deps.getSendHostnameOption(context);
        mHostname = sendHostname ? new HostnameTransliterator().transliterate(
                deps.getDeviceName(mContext)) : null;
    }
    }


    public void registerForPreDhcpNotification() {
    public void registerForPreDhcpNotification() {
@@ -641,7 +649,7 @@ public class DhcpClient extends StateMachine {
    private boolean sendDiscoverPacket() {
    private boolean sendDiscoverPacket() {
        final ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
        final ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
                DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr,
                DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr,
                DO_UNICAST, REQUESTED_PARAMS, isDhcpRapidCommitEnabled());
                DO_UNICAST, REQUESTED_PARAMS, isDhcpRapidCommitEnabled(), mHostname);
        return transmitPacket(packet, "DHCPDISCOVER", DhcpPacket.ENCAP_L2, INADDR_BROADCAST);
        return transmitPacket(packet, "DHCPDISCOVER", DhcpPacket.ENCAP_L2, INADDR_BROADCAST);
    }
    }


@@ -655,7 +663,7 @@ public class DhcpClient extends StateMachine {
        final ByteBuffer packet = DhcpPacket.buildRequestPacket(
        final ByteBuffer packet = DhcpPacket.buildRequestPacket(
                encap, mTransactionId, getSecs(), clientAddress,
                encap, mTransactionId, getSecs(), clientAddress,
                DO_UNICAST, mHwAddr, requestedAddress,
                DO_UNICAST, mHwAddr, requestedAddress,
                serverAddress, REQUESTED_PARAMS, null);
                serverAddress, REQUESTED_PARAMS, mHostname);
        String serverStr = (serverAddress != null) ? serverAddress.getHostAddress() : null;
        String serverStr = (serverAddress != null) ? serverAddress.getHostAddress() : null;
        String description = "DHCPREQUEST ciaddr=" + clientAddress.getHostAddress() +
        String description = "DHCPREQUEST ciaddr=" + clientAddress.getHostAddress() +
                             " request=" + requestedAddress.getHostAddress() +
                             " request=" + requestedAddress.getHostAddress() +
@@ -744,7 +752,7 @@ public class DhcpClient extends StateMachine {
        mDhcpLease = results;
        mDhcpLease = results;
        if (mDhcpLease.dnsServers.isEmpty()) {
        if (mDhcpLease.dnsServers.isEmpty()) {
            // supplement customized dns servers
            // supplement customized dns servers
            String[] dnsServersList =
            final String[] dnsServersList =
                    mContext.getResources().getStringArray(R.array.config_default_dns_servers);
                    mContext.getResources().getStringArray(R.array.config_default_dns_servers);
            for (final String dnsServer : dnsServersList) {
            for (final String dnsServer : dnsServersList) {
                try {
                try {
@@ -1259,7 +1267,7 @@ public class DhcpClient extends StateMachine {
            final Layer2PacketParcelable l2Packet = new Layer2PacketParcelable();
            final Layer2PacketParcelable l2Packet = new Layer2PacketParcelable();
            final ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
            final ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
                    DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr,
                    DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr,
                    DO_UNICAST, REQUESTED_PARAMS, true /* rapid commit */);
                    DO_UNICAST, REQUESTED_PARAMS, true /* rapid commit */, mHostname);


            l2Packet.dstMacAddress = MacAddress.fromBytes(DhcpPacket.ETHER_BROADCAST);
            l2Packet.dstMacAddress = MacAddress.fromBytes(DhcpPacket.ETHER_BROADCAST);
            l2Packet.payload = packet.array();
            l2Packet.payload = packet.array();
@@ -1429,16 +1437,16 @@ public class DhcpClient extends StateMachine {
    //    address being probed for, and the packet's 'sender hardware address' is not the
    //    address being probed for, and the packet's 'sender hardware address' is not the
    //    hardware address of any of the host's interfaces, then the host SHOULD similarly
    //    hardware address of any of the host's interfaces, then the host SHOULD similarly
    //    treat this as an address conflict.
    //    treat this as an address conflict.
    private boolean checkArpSenderIpOrTargetIp(@NonNull ArpPacket packet,
    private boolean packetHasIpAddressConflict(@NonNull ArpPacket packet,
            @NonNull Inet4Address targetIp) {
            @NonNull Inet4Address targetIp) {
        return ((!packet.senderIp.equals(INADDR_ANY) && packet.senderIp.equals(targetIp))
        return (((!packet.senderIp.equals(INADDR_ANY) && packet.senderIp.equals(targetIp))
                || (isArpProbe(packet) && packet.targetIp.equals(targetIp)));
                || (isArpProbe(packet) && packet.targetIp.equals(targetIp)))
                && !Arrays.equals(packet.senderHwAddress.toByteArray(), mHwAddr));
    }
    }


    private boolean hasIpAddressConflict(@NonNull ArpPacket packet,
    private boolean hasIpAddressConflict(@NonNull ArpPacket packet,
            @NonNull Inet4Address targetIp) {
            @NonNull Inet4Address targetIp) {
        if (checkArpSenderIpOrTargetIp(packet, targetIp)
        if (!packetHasIpAddressConflict(packet, targetIp)) return false;
                && !Arrays.equals(packet.senderHwAddress.toByteArray(), mHwAddr)) {
        if (DBG) {
        if (DBG) {
            final String senderIpString = packet.senderIp.getHostAddress();
            final String senderIpString = packet.senderIp.getHostAddress();
            final String targetIpString = packet.targetIp.getHostAddress();
            final String targetIpString = packet.targetIp.getHostAddress();
@@ -1454,8 +1462,6 @@ public class DhcpClient extends StateMachine {
        }
        }
        return true;
        return true;
    }
    }
        return false;
    }


    class IpAddressConflictDetectingState extends LoggingState {
    class IpAddressConflictDetectingState extends LoggingState {
        private int mArpProbeCount;
        private int mArpProbeCount;
@@ -1492,13 +1498,7 @@ public class DhcpClient extends StateMachine {
            }
            }


            // Read the customized parameters from DeviceConfig.
            // Read the customized parameters from DeviceConfig.
            mArpFirstProbeDelayMs = mDependencies.getIntDeviceConfig(ARP_FIRST_PROBE_DELAY_MS);
            readIpConflictParametersFromDeviceConfig();
            mArpProbeMaxDelayMs = mDependencies.getIntDeviceConfig(ARP_PROBE_MAX_MS);
            mArpProbeMinDelayMs = mDependencies.getIntDeviceConfig(ARP_PROBE_MIN_MS);
            mArpAnnounceIntervalMs = mDependencies.getIntDeviceConfig(ARP_ANNOUNCE_INTERVAL_MS);
            mArpFirstAnnounceDelayMs = mDependencies.getIntDeviceConfig(
                    ARP_FIRST_ANNOUNCE_DELAY_MS);

            if (VDBG) {
            if (VDBG) {
                Log.d(TAG, "ARP First Probe delay: "    + mArpFirstProbeDelayMs
                Log.d(TAG, "ARP First Probe delay: "    + mArpFirstProbeDelayMs
                        + " ARP Probe Max delay: "      + mArpProbeMaxDelayMs
                        + " ARP Probe Max delay: "      + mArpProbeMaxDelayMs
@@ -1577,6 +1577,33 @@ public class DhcpClient extends StateMachine {
            removeMessages(EVENT_IP_CONFLICT);
            removeMessages(EVENT_IP_CONFLICT);
        }
        }


        // The following timing parameters are defined in RFC5227 as fixed constants, which
        // are too long to adopt in the mobile network scenario, however more appropriate to
        // reference these fixed value as maximumValue argument to restrict the upper bound,
        // the minimum values of 10/20ms are used to avoid tight loops due to misconfiguration.
        private void readIpConflictParametersFromDeviceConfig() {
            // PROBE_WAIT
            mArpFirstProbeDelayMs = mDependencies.getIntDeviceConfig(ARP_FIRST_PROBE_DELAY_MS,
                    10, MAX_ARP_FIRST_PROBE_DELAY_MS, DEFAULT_ARP_FIRST_PROBE_DELAY_MS);

            // PROBE_MIN
            mArpProbeMinDelayMs = mDependencies.getIntDeviceConfig(ARP_PROBE_MIN_MS, 10,
                    MAX_ARP_PROBE_MIN_MS, DEFAULT_ARP_PROBE_MIN_MS);

            // PROBE_MAX
            mArpProbeMaxDelayMs = Math.max(mArpProbeMinDelayMs + 1,
                    mDependencies.getIntDeviceConfig(ARP_PROBE_MAX_MS, 20, MAX_ARP_PROBE_MAX_MS,
                    DEFAULT_ARP_PROBE_MAX_MS));

            // ANNOUNCE_WAIT
            mArpFirstAnnounceDelayMs = mDependencies.getIntDeviceConfig(ARP_FIRST_ANNOUNCE_DELAY_MS,
                    20, MAX_ARP_FIRST_ANNOUNCE_DELAY_MS, DEFAULT_ARP_FIRST_ANNOUNCE_DELAY_MS);

            // ANNOUNCE_INTERVAL
            mArpAnnounceIntervalMs = mDependencies.getIntDeviceConfig(ARP_ANNOUNCE_INTERVAL_MS, 20,
                    MAX_ARP_ANNOUNCE_INTERVAL_MS, DEFAULT_ARP_ANNOUNCE_INTERVAL_MS);
        }

        private boolean sendArpProbe() {
        private boolean sendArpProbe() {
            return mIpConflictDetector.transmitPacket(mTargetIp /* target IP */,
            return mIpConflictDetector.transmitPacket(mTargetIp /* target IP */,
                    INADDR_ANY /* sender IP */, mHwAddr, mInterfaceBroadcastAddr);
                    INADDR_ANY /* sender IP */, mHwAddr, mInterfaceBroadcastAddr);
@@ -1781,7 +1808,8 @@ public class DhcpClient extends StateMachine {
                return;
                return;
            }
            }


            mTimeout = mDependencies.getIntDeviceConfig(DHCP_RESTART_CONFIG_DELAY);
            mTimeout = mDependencies.getIntDeviceConfig(DHCP_RESTART_CONFIG_DELAY, 100,
                    MAX_DHCP_CLIENT_RESTART_CONFIG_DELAY_MS, DEFAULT_DHCP_RESTART_CONFIG_DELAY_MS);
            super.enter();
            super.enter();
            sendPacket();
            sendPacket();
        }
        }
+30 −5
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2019 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;
package android.net.dhcp;


import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ALL;
import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ALL;
@@ -15,6 +31,8 @@ import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.VisibleForTesting;


import com.android.networkstack.apishim.ShimUtils;

import java.io.UnsupportedEncodingException;
import java.io.UnsupportedEncodingException;
import java.net.Inet4Address;
import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.net.UnknownHostException;
@@ -350,7 +368,6 @@ public abstract class DhcpPacket {
    // Set in unit tests, to ensure that the test does not break when run on different devices and
    // Set in unit tests, to ensure that the test does not break when run on different devices and
    // on different releases.
    // on different releases.
    static String testOverrideVendorId = null;
    static String testOverrideVendorId = null;
    static String testOverrideHostname = null;


    protected DhcpPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp,
    protected DhcpPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp,
                         Inet4Address nextIp, Inet4Address relayIp,
                         Inet4Address nextIp, Inet4Address relayIp,
@@ -724,10 +741,17 @@ public abstract class DhcpPacket {
        return "android-dhcp-" + Build.VERSION.RELEASE;
        return "android-dhcp-" + Build.VERSION.RELEASE;
    }
    }


    private String getHostname() {
    /**
        if (testOverrideHostname != null) return testOverrideHostname;
     * Get the DHCP client hostname after transliteration.
     */
    @VisibleForTesting
    public String getHostname() {
        if (mHostName == null
                && !ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q)) {
            return SystemProperties.get("net.hostname");
            return SystemProperties.get("net.hostname");
        }
        }
        return mHostName;
    }


    /**
    /**
     * Adds common client TLVs.
     * Adds common client TLVs.
@@ -1328,10 +1352,11 @@ public abstract class DhcpPacket {
     */
     */
    public static ByteBuffer buildDiscoverPacket(int encap, int transactionId,
    public static ByteBuffer buildDiscoverPacket(int encap, int transactionId,
            short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams,
            short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams,
            boolean rapidCommit) {
            boolean rapidCommit, String hostname) {
        DhcpPacket pkt = new DhcpDiscoverPacket(transactionId, secs, INADDR_ANY /* relayIp */,
        DhcpPacket pkt = new DhcpDiscoverPacket(transactionId, secs, INADDR_ANY /* relayIp */,
                clientMac, broadcast, INADDR_ANY /* srcIp */, rapidCommit);
                clientMac, broadcast, INADDR_ANY /* srcIp */, rapidCommit);
        pkt.mRequestedParams = expectedParams;
        pkt.mRequestedParams = expectedParams;
        pkt.mHostName = hostname;
        return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
        return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
    }
    }


+103 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2019 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.util;

import android.icu.text.Transliterator;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;

import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;

/**
 * Transliterator to display a human-readable DHCP client hostname.
 */
public class HostnameTransliterator {
    private static final String TAG = "HostnameTransliterator";

    // Maximum length of hostname to be encoded in the DHCP message. Following RFC1035#2.3.4
    // and this transliterator converts the device name to a single label, so the label length
    // limit applies to the whole hostname.
    private static final int MAX_DNS_LABEL_LENGTH = 63;

    @Nullable
    private final Transliterator mTransliterator;

    public HostnameTransliterator() {
        final Enumeration<String> availableIDs = Transliterator.getAvailableIDs();
        final Set<String> actualIds = new HashSet<>(Collections.list(availableIDs));
        final StringBuilder rules = new StringBuilder();
        if (actualIds.contains("Any-ASCII")) {
            rules.append(":: Any-ASCII; ");
        } else if (actualIds.contains("Any-Latin") && actualIds.contains("Latin-ASCII")) {
            rules.append(":: Any-Latin; :: Latin-ASCII; ");
        } else {
            Log.e(TAG, "ICU Transliterator doesn't include supported ID");
            mTransliterator = null;
            return;
        }
        mTransliterator = Transliterator.createFromRules("", rules.toString(),
                Transliterator.FORWARD);
    }

    @VisibleForTesting
    public HostnameTransliterator(Transliterator transliterator) {
        mTransliterator = transliterator;
    }

    // RFC952 and RFC1123 stipulates an valid hostname should be:
    // 1. Only contain the alphabet (A-Z, a-z), digits (0-9), minus sign (-).
    // 2. No blank or space characters are permitted as part of a name.
    // 3. The first character must be an alpha character or digit.
    // 4. The last character must not be a minus sign (-).
    private String maybeRemoveRedundantSymbols(@NonNull String string) {
        String result = string.replaceAll("[^a-zA-Z0-9-]", "-");
        result = result.replaceAll("-+", "-");
        if (result.startsWith("-")) {
            result = result.replaceFirst("-", "");
        }
        if (result.endsWith("-")) {
            result = result.substring(0, result.length() - 1);
        }
        return result;
    }

    /**
     *  Transliterate the device name to valid hostname that could be human-readable string.
     */
    public String transliterate(@NonNull String deviceName) {
        if (deviceName == null) return null;
        if (mTransliterator == null) {
            if (!deviceName.matches("\\p{ASCII}*")) return null;
            deviceName = maybeRemoveRedundantSymbols(deviceName);
            if (TextUtils.isEmpty(deviceName)) return null;
            return deviceName.length() > MAX_DNS_LABEL_LENGTH
                    ? deviceName.substring(0, MAX_DNS_LABEL_LENGTH) : deviceName;
        }

        String hostname = maybeRemoveRedundantSymbols(mTransliterator.transliterate(deviceName));
        if (TextUtils.isEmpty(hostname)) return null;
        return hostname.length() > MAX_DNS_LABEL_LENGTH
                ? hostname.substring(0, MAX_DNS_LABEL_LENGTH) : hostname;
    }
}
Loading