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