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

Commit e1aa745f authored by Xiao Ma's avatar Xiao Ma Committed by Gerrit Code Review
Browse files

Merge "Add captive portal info to DhcpClient output"

parents 13fc7dee 2a738929
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import android.os.Build;
import android.os.RemoteException;

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

import org.json.JSONException;
import org.json.JSONObject;
@@ -70,7 +69,6 @@ public class CaptivePortalDataShimImpl
                .build());
    }

    @VisibleForTesting
    public static boolean isSupported() {
        return ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q);
    }
+26 −6
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.net.dhcp;

import static android.net.dhcp.DhcpPacket.DHCP_BROADCAST_ADDRESS;
import static android.net.dhcp.DhcpPacket.DHCP_CAPTIVE_PORTAL;
import static android.net.dhcp.DhcpPacket.DHCP_DNS_SERVER;
import static android.net.dhcp.DhcpPacket.DHCP_DOMAIN_NAME;
import static android.net.dhcp.DhcpPacket.DHCP_LEASE_TIME;
@@ -95,6 +96,7 @@ import com.android.internal.util.StateMachine;
import com.android.internal.util.TrafficStatsConstants;
import com.android.internal.util.WakeupMessage;
import com.android.networkstack.R;
import com.android.networkstack.apishim.CaptivePortalDataShimImpl;
import com.android.networkstack.apishim.SocketUtilsShimImpl;
import com.android.networkstack.arp.ArpPacket;

@@ -260,8 +262,9 @@ public class DhcpClient extends StateMachine {
    private static final SparseArray<String> sMessageNames =
            MessageUtils.findMessageNames(sMessageClasses);

    // DHCP parameters that we request.
    /* package */ static final byte[] REQUESTED_PARAMS = new byte[] {
    // DHCP parameters that we request by default.
    @VisibleForTesting
    /* package */ static final byte[] DEFAULT_REQUESTED_PARAMS = new byte[] {
        DHCP_SUBNET_MASK,
        DHCP_ROUTER,
        DHCP_DNS_SERVER,
@@ -274,6 +277,21 @@ public class DhcpClient extends StateMachine {
        DHCP_VENDOR_INFO,
    };

    @NonNull
    private byte[] getRequestedParams() {
        if (isCapportApiEnabled()) {
            final byte[] params = Arrays.copyOf(DEFAULT_REQUESTED_PARAMS,
                    DEFAULT_REQUESTED_PARAMS.length + 1);
            params[params.length - 1] = DHCP_CAPTIVE_PORTAL;
            return params;
        }
        return DEFAULT_REQUESTED_PARAMS;
    }

    private static boolean isCapportApiEnabled() {
        return CaptivePortalDataShimImpl.isSupported();
    }

    // DHCP flag that means "yes, we support unicast."
    private static final boolean DO_UNICAST   = false;

@@ -556,8 +574,10 @@ public class DhcpClient extends StateMachine {
        @Override
        protected void handlePacket(byte[] recvbuf, int length) {
            try {
                final byte[] optionsToSkip =
                        isCapportApiEnabled() ? new byte[0] : new byte[] { DHCP_CAPTIVE_PORTAL };
                final DhcpPacket packet = DhcpPacket.decodeFullPacket(recvbuf, length,
                        DhcpPacket.ENCAP_L2);
                        DhcpPacket.ENCAP_L2, optionsToSkip);
                if (DBG) Log.d(TAG, "Received packet: " + packet);
                sendMessage(CMD_RECEIVED_PACKET, packet);
            } catch (DhcpPacket.ParseException e) {
@@ -649,7 +669,7 @@ public class DhcpClient extends StateMachine {
    private boolean sendDiscoverPacket() {
        final ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
                DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr,
                DO_UNICAST, REQUESTED_PARAMS, isDhcpRapidCommitEnabled(), mHostname);
                DO_UNICAST, getRequestedParams(), isDhcpRapidCommitEnabled(), mHostname);
        return transmitPacket(packet, "DHCPDISCOVER", DhcpPacket.ENCAP_L2, INADDR_BROADCAST);
    }

@@ -663,7 +683,7 @@ public class DhcpClient extends StateMachine {
        final ByteBuffer packet = DhcpPacket.buildRequestPacket(
                encap, mTransactionId, getSecs(), clientAddress,
                DO_UNICAST, mHwAddr, requestedAddress,
                serverAddress, REQUESTED_PARAMS, mHostname);
                serverAddress, getRequestedParams(), mHostname);
        String serverStr = (serverAddress != null) ? serverAddress.getHostAddress() : null;
        String description = "DHCPREQUEST ciaddr=" + clientAddress.getHostAddress() +
                             " request=" + requestedAddress.getHostAddress() +
@@ -1267,7 +1287,7 @@ public class DhcpClient extends StateMachine {
            final Layer2PacketParcelable l2Packet = new Layer2PacketParcelable();
            final ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
                    DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr,
                    DO_UNICAST, REQUESTED_PARAMS, true /* rapid commit */, mHostname);
                    DO_UNICAST, getRequestedParams(), true /* rapid commit */, mHostname);

            l2Packet.dstMacAddress = MacAddress.fromBytes(DhcpPacket.ETHER_BROADCAST);
            l2Packet.payload = Arrays.copyOf(packet.array(), packet.limit());
+52 −12
Original line number Diff line number Diff line
@@ -307,6 +307,10 @@ public abstract class DhcpPacket {
    protected static final byte DHCP_RAPID_COMMIT = 80;
    protected boolean mRapidCommit;

    @VisibleForTesting
    public static final byte DHCP_CAPTIVE_PORTAL = (byte) 114;
    protected String mCaptivePortalUrl;

    /**
     * DHCP zero-length option code: pad
     */
@@ -785,6 +789,7 @@ public abstract class DhcpPacket {
        if (mMtu != null && Short.toUnsignedInt(mMtu) >= IPV4_MIN_MTU) {
            addTlv(buf, DHCP_MTU, mMtu);
        }
        addTlv(buf, DHCP_CAPTIVE_PORTAL, mCaptivePortalUrl);
    }

    /**
@@ -871,6 +876,23 @@ public abstract class DhcpPacket {
        }
    }

    private static int skipOption(ByteBuffer packet, int optionLen)
            throws BufferUnderflowException {
        int expectedLen = 0;
        for (int i = 0; i < optionLen; i++) {
            expectedLen++;
            packet.get();
        }
        return expectedLen;
    }

    private static boolean shouldSkipOption(byte optionType, byte[] optionsToSkip) {
        for (byte option : optionsToSkip) {
            if (option == optionType) return true;
        }
        return false;
    }

    /**
     * Creates a concrete DhcpPacket from the supplied ByteBuffer.  The
     * buffer may have an L2 encapsulation (which is the full EthernetII
@@ -881,8 +903,8 @@ public abstract class DhcpPacket {
     * in object fields.
     */
    @VisibleForTesting
    static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException
    {
    static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType, byte[] optionsToSkip)
            throws ParseException {
        // bootp parameters
        int transactionId;
        short secs;
@@ -900,6 +922,7 @@ public abstract class DhcpPacket {
        String vendorId = null;
        String vendorInfo = null;
        boolean rapidCommit = false;
        String captivePortalUrl = null;
        byte[] expectedParams = null;
        String hostName = null;
        String domainName = null;
@@ -1080,6 +1103,11 @@ public abstract class DhcpPacket {
                    int optionLen = packet.get() & 0xFF;
                    int expectedLen = 0;

                    if (shouldSkipOption(optionType, optionsToSkip)) {
                        skipOption(packet, optionLen);
                        continue;
                    }

                    switch(optionType) {
                        case DHCP_SUBNET_MASK:
                            netMask = readIpAddress(packet);
@@ -1172,12 +1200,12 @@ public abstract class DhcpPacket {
                            expectedLen = 0;
                            rapidCommit = true;
                            break;
                        case DHCP_CAPTIVE_PORTAL:
                            expectedLen = optionLen;
                            captivePortalUrl = readAsciiString(packet, optionLen, true);
                            break;
                        default:
                            // ignore any other parameters
                            for (int i = 0; i < optionLen; i++) {
                                expectedLen++;
                                byte throwaway = packet.get();
                            }
                            expectedLen = skipOption(packet, optionLen);
                    }

                    if (expectedLen != optionLen) {
@@ -1263,6 +1291,7 @@ public abstract class DhcpPacket {
        newPacket.mT2 = T2;
        newPacket.mVendorId = vendorId;
        newPacket.mVendorInfo = vendorInfo;
        newPacket.mCaptivePortalUrl = captivePortalUrl;
        if ((optionOverload & OPTION_OVERLOAD_SNAME) == 0) {
            newPacket.mServerHostName = serverHostName;
        } else {
@@ -1274,11 +1303,11 @@ public abstract class DhcpPacket {
    /**
     * Parse a packet from an array of bytes, stopping at the given length.
     */
    public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType)
            throws ParseException {
    public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType,
            byte[] optionsToSkip) throws ParseException {
        ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN);
        try {
            return decodeFullPacket(buffer, pktType);
            return decodeFullPacket(buffer, pktType, optionsToSkip);
        } catch (ParseException e) {
            throw e;
        } catch (Exception e) {
@@ -1286,6 +1315,14 @@ public abstract class DhcpPacket {
        }
    }

    /**
     * Parse a packet from an array of bytes, stopping at the given length.
     */
    public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType)
            throws ParseException {
        return decodeFullPacket(packet, length, pktType, new byte[0]);
    }

    /**
     *  Construct a DhcpResults object from a DHCP reply packet.
     */
@@ -1328,6 +1365,7 @@ public abstract class DhcpPacket {
        results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE;
        results.mtu = (mMtu != null && MIN_MTU <= mMtu && mMtu <= MAX_MTU) ? mMtu : 0;
        results.serverHostName = mServerHostName;
        results.captivePortalApiUrl = mCaptivePortalUrl;

        return results;
    }
@@ -1369,7 +1407,7 @@ public abstract class DhcpPacket {
            Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask,
            Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
            Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered,
            short mtu) {
            short mtu, String captivePortalUrl) {
        DhcpPacket pkt = new DhcpOfferPacket(
                transactionId, (short) 0, broadcast, serverIpAddr, relayIp,
                INADDR_ANY /* clientIp */, yourIp, mac);
@@ -1382,6 +1420,7 @@ public abstract class DhcpPacket {
        pkt.mSubnetMask = netMask;
        pkt.mBroadcastAddress = bcAddr;
        pkt.mMtu = mtu;
        pkt.mCaptivePortalUrl = captivePortalUrl;
        if (metered) {
            pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
        }
@@ -1396,7 +1435,7 @@ public abstract class DhcpPacket {
            Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask,
            Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
            Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered,
            short mtu, boolean rapidCommit) {
            short mtu, boolean rapidCommit, String captivePortalUrl) {
        DhcpPacket pkt = new DhcpAckPacket(
                transactionId, (short) 0, broadcast, serverIpAddr, relayIp, requestClientIp, yourIp,
                mac, rapidCommit);
@@ -1409,6 +1448,7 @@ public abstract class DhcpPacket {
        pkt.mServerIdentifier = dhcpServerIdentifier;
        pkt.mBroadcastAddress = bcAddr;
        pkt.mMtu = mtu;
        pkt.mCaptivePortalUrl = captivePortalUrl;
        if (metered) {
            pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
        }
+5 −2
Original line number Diff line number Diff line
@@ -529,7 +529,9 @@ public class DhcpServer extends IDhcpServer.Stub {
                broadcastAddr, new ArrayList<>(mServingParams.defaultRouters),
                new ArrayList<>(mServingParams.dnsServers),
                mServingParams.getServerInet4Addr(), null /* domainName */, hostname,
                mServingParams.metered, (short) mServingParams.linkMtu);
                mServingParams.metered, (short) mServingParams.linkMtu,
                // TODO (b/144402437): advertise the URL if known
                null /* captivePortalApiUrl */);

        return transmitOfferOrAckPacket(offerPacket, request, lease, clientMac, broadcastFlag);
    }
@@ -549,7 +551,8 @@ public class DhcpServer extends IDhcpServer.Stub {
                new ArrayList<>(mServingParams.dnsServers),
                mServingParams.getServerInet4Addr(), null /* domainName */, hostname,
                mServingParams.metered, (short) mServingParams.linkMtu,
                packet.mRapidCommit && mDhcpRapidCommitEnabled);
                // TODO (b/144402437): advertise the URL if known
                packet.mRapidCommit && mDhcpRapidCommitEnabled, null /* captivePortalApiUrl */);

        return transmitOfferOrAckPacket(ackPacket, packet, lease, clientMac, broadcastFlag);
    }
+11 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import android.net.ProvisioningConfigurationParcelable;
import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.net.TcpKeepalivePacketDataParcelable;
import android.net.Uri;
import android.net.apf.ApfCapabilities;
import android.net.apf.ApfFilter;
import android.net.dhcp.DhcpClient;
@@ -57,6 +58,7 @@ import android.text.TextUtils;
import android.util.LocalLog;
import android.util.Log;
import android.util.Pair;
import android.util.Patterns;
import android.util.SparseArray;

import androidx.annotation.NonNull;
@@ -1192,6 +1194,15 @@ public class IpClient extends StateMachine {
            if (mDhcpResults.mtu != 0) {
                newLp.setMtu(mDhcpResults.mtu);
            }

            final String capportUrl = mDhcpResults.captivePortalApiUrl;
            // Uri.parse does no syntax check; do a simple regex check to eliminate garbage.
            // If the URL is still incorrect data fetching will fail later, which is fine.
            if (capportUrl != null && Patterns.WEB_URL.matcher(capportUrl).matches()) {
                NetworkInformationShimImpl.newInstance()
                        .setCaptivePortalApiUrl(newLp, Uri.parse(capportUrl));
            }
            // TODO: also look at the IPv6 RA (netlink) for captive portal URL
        }

        // [4] Add in TCP buffer sizes and HTTP Proxy config, if available.
Loading