1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.connectivity; 18 19 import android.system.OsConstants; 20 import android.net.ConnectivityManager; 21 import android.net.NetworkUtils; 22 import android.net.util.IpUtils; 23 24 import java.net.Inet4Address; 25 import java.net.Inet6Address; 26 import java.net.InetAddress; 27 import java.nio.ByteBuffer; 28 import java.nio.ByteOrder; 29 30 import static android.net.ConnectivityManager.PacketKeepalive.*; 31 32 /** 33 * Represents the actual packets that are sent by the 34 * {@link android.net.ConnectivityManager.PacketKeepalive} API. 35 * 36 * @hide 37 */ 38 public class KeepalivePacketData { 39 /** Protocol of the packet to send; one of the OsConstants.ETH_P_* values. */ 40 public final int protocol; 41 42 /** Source IP address */ 43 public final InetAddress srcAddress; 44 45 /** Destination IP address */ 46 public final InetAddress dstAddress; 47 48 /** Source port */ 49 public final int srcPort; 50 51 /** Destination port */ 52 public final int dstPort; 53 54 /** Destination MAC address. Can change if routing changes. */ 55 public byte[] dstMac; 56 57 /** Packet data. A raw byte string of packet data, not including the link-layer header. */ 58 public final byte[] data; 59 60 private static final int IPV4_HEADER_LENGTH = 20; 61 private static final int UDP_HEADER_LENGTH = 8; 62 63 protected KeepalivePacketData(InetAddress srcAddress, int srcPort, 64 InetAddress dstAddress, int dstPort, byte[] data) throws InvalidPacketException { 65 this.srcAddress = srcAddress; 66 this.dstAddress = dstAddress; 67 this.srcPort = srcPort; 68 this.dstPort = dstPort; 69 this.data = data; 70 71 // Check we have two IP addresses of the same family. 72 if (srcAddress == null || dstAddress == null || 73 !srcAddress.getClass().getName().equals(dstAddress.getClass().getName())) { 74 throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS); 75 } 76 77 // Set the protocol. 78 if (this.dstAddress instanceof Inet4Address) { 79 this.protocol = OsConstants.ETH_P_IP; 80 } else if (this.dstAddress instanceof Inet6Address) { 81 this.protocol = OsConstants.ETH_P_IPV6; 82 } else { 83 throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS); 84 } 85 86 // Check the ports. 87 if (!IpUtils.isValidUdpOrTcpPort(srcPort) || !IpUtils.isValidUdpOrTcpPort(dstPort)) { 88 throw new InvalidPacketException(ERROR_INVALID_PORT); 89 } 90 } 91 92 public static class InvalidPacketException extends Exception { 93 final public int error; 94 public InvalidPacketException(int error) { 95 this.error = error; 96 } 97 } 98 99 /** 100 * Creates an IPsec NAT-T keepalive packet with the specified parameters. 101 */ 102 public static KeepalivePacketData nattKeepalivePacket( 103 InetAddress srcAddress, int srcPort, 104 InetAddress dstAddress, int dstPort) throws InvalidPacketException { 105 106 if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) { 107 throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS); 108 } 109 110 if (dstPort != NATT_PORT) { 111 throw new InvalidPacketException(ERROR_INVALID_PORT); 112 } 113 114 int length = IPV4_HEADER_LENGTH + UDP_HEADER_LENGTH + 1; 115 ByteBuffer buf = ByteBuffer.allocate(length); 116 buf.order(ByteOrder.BIG_ENDIAN); 117 buf.putShort((short) 0x4500); // IP version and TOS 118 buf.putShort((short) length); 119 buf.putInt(0); // ID, flags, offset 120 buf.put((byte) 64); // TTL 121 buf.put((byte) OsConstants.IPPROTO_UDP); 122 int ipChecksumOffset = buf.position(); 123 buf.putShort((short) 0); // IP checksum 124 buf.put(srcAddress.getAddress()); 125 buf.put(dstAddress.getAddress()); 126 buf.putShort((short) srcPort); 127 buf.putShort((short) dstPort); 128 buf.putShort((short) (length - 20)); // UDP length 129 int udpChecksumOffset = buf.position(); 130 buf.putShort((short) 0); // UDP checksum 131 buf.put((byte) 0xff); // NAT-T keepalive 132 buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0)); 133 buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_LENGTH)); 134 135 return new KeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array()); 136 } 137 } 138