18bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti/*
28bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * Copyright (C) 2015 The Android Open Source Project
38bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti *
48bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * Licensed under the Apache License, Version 2.0 (the "License");
58bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * you may not use this file except in compliance with the License.
68bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * You may obtain a copy of the License at
78bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti *
88bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti *      http://www.apache.org/licenses/LICENSE-2.0
98bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti *
108bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * Unless required by applicable law or agreed to in writing, software
118bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * distributed under the License is distributed on an "AS IS" BASIS,
128bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * See the License for the specific language governing permissions and
148bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * limitations under the License.
158bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti */
168bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
178bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittipackage com.android.server.connectivity;
188bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
198bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittiimport android.system.OsConstants;
208bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittiimport android.net.ConnectivityManager;
218bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittiimport android.net.NetworkUtils;
228bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittiimport android.net.util.IpUtils;
238bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
248bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittiimport java.net.Inet4Address;
258bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittiimport java.net.Inet6Address;
268bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittiimport java.net.InetAddress;
278bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittiimport java.nio.ByteBuffer;
288bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittiimport java.nio.ByteOrder;
298bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
308bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittiimport static android.net.ConnectivityManager.PacketKeepalive.*;
318bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
328bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti/**
338bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * Represents the actual packets that are sent by the
348bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * {@link android.net.ConnectivityManager.PacketKeepalive} API.
358bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti *
368bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * @hide
378bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti */
388bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittipublic class KeepalivePacketData {
398bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    /** Protocol of the packet to send; one of the OsConstants.ETH_P_* values. */
408bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    public final int protocol;
418bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
428bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    /** Source IP address */
438bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    public final InetAddress srcAddress;
448bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
458bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    /** Destination IP address */
468bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    public final InetAddress dstAddress;
478bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
488bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    /** Source port */
498bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    public final int srcPort;
508bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
518bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    /** Destination port */
528bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    public final int dstPort;
538bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
548bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    /** Destination MAC address. Can change if routing changes. */
558bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    public byte[] dstMac;
568bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
578bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    /** Packet data. A raw byte string of packet data, not including the link-layer header. */
588bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    public final byte[] data;
598bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
608bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    private static final int IPV4_HEADER_LENGTH = 20;
618bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    private static final int UDP_HEADER_LENGTH = 8;
628bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
638bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    protected KeepalivePacketData(InetAddress srcAddress, int srcPort,
648bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti            InetAddress dstAddress, int dstPort, byte[] data) throws InvalidPacketException {
658bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        this.srcAddress = srcAddress;
668bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        this.dstAddress = dstAddress;
678bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        this.srcPort = srcPort;
688bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        this.dstPort = dstPort;
698bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        this.data = data;
708bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
718bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        // Check we have two IP addresses of the same family.
728bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        if (srcAddress == null || dstAddress == null ||
738bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti                !srcAddress.getClass().getName().equals(dstAddress.getClass().getName())) {
749acca09527eedfd5e9b2797eec4864fb46a699d7Lorenzo Colitti            throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
758bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        }
768bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
778bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        // Set the protocol.
788bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        if (this.dstAddress instanceof Inet4Address) {
798bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti            this.protocol = OsConstants.ETH_P_IP;
808bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        } else if (this.dstAddress instanceof Inet6Address) {
818bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti            this.protocol = OsConstants.ETH_P_IPV6;
828bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        } else {
838bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti            throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
848bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        }
858bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
868bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        // Check the ports.
878bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        if (!IpUtils.isValidUdpOrTcpPort(srcPort) || !IpUtils.isValidUdpOrTcpPort(dstPort)) {
888bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti            throw new InvalidPacketException(ERROR_INVALID_PORT);
898bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        }
908bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    }
918bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
928bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    public static class InvalidPacketException extends Exception {
938bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        final public int error;
948bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        public InvalidPacketException(int error) {
958bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti            this.error = error;
968bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        }
978bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    }
988bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
998bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    /**
1008bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti     * Creates an IPsec NAT-T keepalive packet with the specified parameters.
1018bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti     */
1028bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    public static KeepalivePacketData nattKeepalivePacket(
1038bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti            InetAddress srcAddress, int srcPort,
1048bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti            InetAddress dstAddress, int dstPort) throws InvalidPacketException {
1058bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
1069acca09527eedfd5e9b2797eec4864fb46a699d7Lorenzo Colitti        if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) {
1078bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti            throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
1088bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        }
1098bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
1108bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        if (dstPort != NATT_PORT) {
1118bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti            throw new InvalidPacketException(ERROR_INVALID_PORT);
1128bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        }
1138bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
1148bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        int length = IPV4_HEADER_LENGTH + UDP_HEADER_LENGTH + 1;
1158bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        ByteBuffer buf = ByteBuffer.allocate(length);
1168bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        buf.order(ByteOrder.BIG_ENDIAN);
1178bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        buf.putShort((short) 0x4500);             // IP version and TOS
1188bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        buf.putShort((short) length);
1198bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        buf.putInt(0);                            // ID, flags, offset
1208bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        buf.put((byte) 64);                       // TTL
1218bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        buf.put((byte) OsConstants.IPPROTO_UDP);
1228bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        int ipChecksumOffset = buf.position();
1238bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        buf.putShort((short) 0);                  // IP checksum
1248bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        buf.put(srcAddress.getAddress());
1258bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        buf.put(dstAddress.getAddress());
1268bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        buf.putShort((short) srcPort);
1278bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        buf.putShort((short) dstPort);
1288bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        buf.putShort((short) (length - 20));      // UDP length
1298bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        int udpChecksumOffset = buf.position();
1308bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        buf.putShort((short) 0);                  // UDP checksum
1318bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        buf.put((byte) 0xff);                     // NAT-T keepalive
1328bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0));
1338bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_LENGTH));
1348bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti
1358bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti        return new KeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array());
1368bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti    }
1378bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti}
138