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

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

Merge "Implement IPv4 address conflict detection and DHCPDECLINE."

parents cd588dee 7d73395d
Loading
Loading
Loading
Loading
+391 −19

File changed.

Preview size limit exceeded, changes collapsed.

+6 −2
Original line number Diff line number Diff line
@@ -27,9 +27,11 @@ public class DhcpDeclinePacket extends DhcpPacket {
     * Generates a DECLINE packet with the specified parameters.
     */
    DhcpDeclinePacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp,
                      Inet4Address nextIp, Inet4Address relayIp,
                      byte[] clientMac) {
                      Inet4Address nextIp, Inet4Address relayIp, byte[] clientMac,
                      Inet4Address requestedIpAddress, Inet4Address serverIdentifier) {
        super(transId, secs, clientIp, yourIp, nextIp, relayIp, clientMac, false);
        mRequestedIp = requestedIpAddress;
        mServerIdentifier = serverIdentifier;
    }

    public String toString() {
@@ -55,6 +57,8 @@ public class DhcpDeclinePacket extends DhcpPacket {
    void finishPacket(ByteBuffer buffer) {
        addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_DECLINE);
        addTlv(buffer, DHCP_CLIENT_IDENTIFIER, getClientId());
        addTlv(buffer, DHCP_REQUESTED_IP, mRequestedIp);
        addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier);
        // RFC 2131 says we MUST NOT include our common client TLVs or the parameter request list.
        addTlvEnd(buffer);
    }
+31 −17
Original line number Diff line number Diff line
@@ -210,7 +210,8 @@ public abstract class DhcpPacket {
     * DHCP Optional Type: DHCP Requested IP Address
     */
    protected static final byte DHCP_REQUESTED_IP = 50;
    protected Inet4Address mRequestedIp;
    @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
    public Inet4Address mRequestedIp;

    /**
     * DHCP Optional Type: DHCP Lease Time
@@ -236,7 +237,8 @@ public abstract class DhcpPacket {
     * DHCP Optional Type: DHCP Server Identifier
     */
    protected static final byte DHCP_SERVER_IDENTIFIER = 54;
    protected Inet4Address mServerIdentifier;
    @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
    public Inet4Address mServerIdentifier;

    /**
     * DHCP Optional Type: DHCP Parameter List
@@ -1189,8 +1191,8 @@ public abstract class DhcpPacket {
                break;
            case DHCP_MESSAGE_TYPE_DECLINE:
                newPacket = new DhcpDeclinePacket(
                    transactionId, secs, clientIp, yourIp, nextIp, relayIp,
                    clientMac);
                    transactionId, secs, clientIp, yourIp, nextIp, relayIp, clientMac, requestedIp,
                    serverIdentifier);
                break;
            case DHCP_MESSAGE_TYPE_ACK:
                newPacket = new DhcpAckPacket(
@@ -1417,4 +1419,16 @@ public abstract class DhcpPacket {
        ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
        return result;
    }

    /**
     * Builds a DHCP-DECLINE packet from the required specified parameters.
     */
    public static ByteBuffer buildDeclinePacket(int encap, int transactionId, byte[] clientMac,
            Inet4Address requestedIpAddress, Inet4Address serverIdentifier) {
        DhcpPacket pkt = new DhcpDeclinePacket(transactionId, (short) 0 /* secs */,
                INADDR_ANY /* clientIp */, INADDR_ANY /* yourIp */, INADDR_ANY /* nextIp */,
                INADDR_ANY /* relayIp */, clientMac, requestedIpAddress, serverIdentifier);
        ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
        return result;
    }
}
+15 −0
Original line number Diff line number Diff line
@@ -121,6 +121,21 @@ public class NetworkStackUtils {
     */
    public static final String DHCP_RAPID_COMMIT_ENABLED = "dhcp_rapid_commit_enabled";

    /**
     * Minimum module version at which to enable the DHCP INIT-REBOOT state.
     */
    public static final String DHCP_INIT_REBOOT_VERSION = "dhcp_init_reboot_version";

    /**
     * Minimum module version at which to enable the DHCP Rapid Commit option.
     */
    public static final String DHCP_RAPID_COMMIT_VERSION = "dhcp_rapid_commit_version";

    /**
     * Minimum module version at which to enable the IP address conflict detection feature.
     */
    public static final String DHCP_IP_CONFLICT_DETECT_VERSION = "dhcp_ip_conflict_detect_version";

    static {
        System.loadLibrary("networkstackutilsjni");
    }
+171 −0
Original line number 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 com.android.networkstack.arp;

import static android.system.OsConstants.ETH_P_ARP;
import static android.system.OsConstants.ETH_P_IP;

import static com.android.server.util.NetworkStackConstants.ARP_ETHER_IPV4_LEN;
import static com.android.server.util.NetworkStackConstants.ARP_HWTYPE_ETHER;
import static com.android.server.util.NetworkStackConstants.ARP_REPLY;
import static com.android.server.util.NetworkStackConstants.ARP_REQUEST;
import static com.android.server.util.NetworkStackConstants.ETHER_ADDR_LEN;
import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_LEN;

import android.net.MacAddress;

import com.android.internal.annotations.VisibleForTesting;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;

/**
 * Defines basic data and operations needed to build and parse packets for the
 * ARP protocol.
 *
 * @hide
 */
public class ArpPacket {
    private static final String TAG = "ArpPacket";

    public final short opCode;
    public final Inet4Address senderIp;
    public final Inet4Address targetIp;
    public final MacAddress senderHwAddress;
    public final MacAddress targetHwAddress;

    ArpPacket(short opCode, MacAddress senderHwAddress, Inet4Address senderIp,
            MacAddress targetHwAddress, Inet4Address targetIp) {
        this.opCode = opCode;
        this.senderHwAddress = senderHwAddress;
        this.senderIp = senderIp;
        this.targetHwAddress = targetHwAddress;
        this.targetIp = targetIp;
    }

    /**
     * Build an ARP packet from the required specified parameters.
     */
    @VisibleForTesting
    public static ByteBuffer buildArpPacket(final byte[] dstMac, final byte[] srcMac,
            final byte[] targetIp, final byte[] targetHwAddress, byte[] senderIp,
            final short opCode) {
        final ByteBuffer buf = ByteBuffer.allocate(ARP_ETHER_IPV4_LEN);

        // Ether header
        buf.put(dstMac);
        buf.put(srcMac);
        buf.putShort((short) ETH_P_ARP);

        // ARP header
        buf.putShort((short) ARP_HWTYPE_ETHER);  // hrd
        buf.putShort((short) ETH_P_IP);          // pro
        buf.put((byte) ETHER_ADDR_LEN);          // hln
        buf.put((byte) IPV4_ADDR_LEN);           // pln
        buf.putShort(opCode);                    // op
        buf.put(srcMac);                         // sha
        buf.put(senderIp);                       // spa
        buf.put(targetHwAddress);                // tha
        buf.put(targetIp);                       // tpa
        buf.flip();
        return buf;
    }

    /**
     * Parse an ARP packet from an ByteBuffer object.
     */
    @VisibleForTesting
    public static ArpPacket parseArpPacket(final byte[] recvbuf, final int length)
            throws ParseException {
        try {
            if (length < ARP_ETHER_IPV4_LEN || recvbuf.length < length) {
                throw new ParseException("Invalid packet length: " + length);
            }

            final ByteBuffer buffer = ByteBuffer.wrap(recvbuf, 0, length);
            byte[] l2dst = new byte[ETHER_ADDR_LEN];
            byte[] l2src = new byte[ETHER_ADDR_LEN];
            buffer.get(l2dst);
            buffer.get(l2src);

            final short etherType = buffer.getShort();
            if (etherType != ETH_P_ARP) {
                throw new ParseException("Incorrect Ether Type: " + etherType);
            }

            final short hwType = buffer.getShort();
            if (hwType != ARP_HWTYPE_ETHER) {
                throw new ParseException("Incorrect HW Type: " + hwType);
            }

            final short protoType = buffer.getShort();
            if (protoType != ETH_P_IP) {
                throw new ParseException("Incorrect Protocol Type: " + protoType);
            }

            final byte hwAddrLength = buffer.get();
            if (hwAddrLength != ETHER_ADDR_LEN) {
                throw new ParseException("Incorrect HW address length: " + hwAddrLength);
            }

            final byte ipAddrLength = buffer.get();
            if (ipAddrLength != IPV4_ADDR_LEN) {
                throw new ParseException("Incorrect Protocol address length: " + ipAddrLength);
            }

            final short opCode = buffer.getShort();
            if (opCode != ARP_REQUEST && opCode != ARP_REPLY) {
                throw new ParseException("Incorrect opCode: " + opCode);
            }

            byte[] senderHwAddress = new byte[ETHER_ADDR_LEN];
            byte[] senderIp = new byte[IPV4_ADDR_LEN];
            buffer.get(senderHwAddress);
            buffer.get(senderIp);

            byte[] targetHwAddress = new byte[ETHER_ADDR_LEN];
            byte[] targetIp = new byte[IPV4_ADDR_LEN];
            buffer.get(targetHwAddress);
            buffer.get(targetIp);

            return new ArpPacket(opCode, MacAddress.fromBytes(senderHwAddress),
                    (Inet4Address) InetAddress.getByAddress(senderIp),
                    MacAddress.fromBytes(targetHwAddress),
                    (Inet4Address) InetAddress.getByAddress(targetIp));
        } catch (IndexOutOfBoundsException e) {
            throw new ParseException("Invalid index when wrapping a byte array into a buffer");
        } catch (BufferUnderflowException e) {
            throw new ParseException("Invalid buffer position");
        } catch (IllegalArgumentException e) {
            throw new ParseException("Invalid MAC address representation");
        } catch (UnknownHostException e) {
            throw new ParseException("Invalid IP address of Host");
        }
    }

    /**
     * Thrown when parsing ARP packet failed.
     */
    public static class ParseException extends Exception {
        ParseException(String message) {
            super(message);
        }
    }
}
Loading