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 android.net; 18 19 import static android.net.ConnectivityManager.PacketKeepalive.*; 20 21 import android.net.util.IpUtils; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 import android.system.OsConstants; 25 import android.util.Log; 26 27 import java.net.Inet4Address; 28 import java.net.InetAddress; 29 import java.nio.ByteBuffer; 30 import java.nio.ByteOrder; 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 implements Parcelable { 39 private static final String TAG = "KeepalivePacketData"; 40 41 /** Source IP address */ 42 public final InetAddress srcAddress; 43 44 /** Destination IP address */ 45 public final InetAddress dstAddress; 46 47 /** Source port */ 48 public final int srcPort; 49 50 /** Destination port */ 51 public final int dstPort; 52 53 /** Packet data. A raw byte string of packet data, not including the link-layer header. */ 54 private final byte[] mPacket; 55 56 private static final int IPV4_HEADER_LENGTH = 20; 57 private static final int UDP_HEADER_LENGTH = 8; 58 59 // This should only be constructed via static factory methods, such as 60 // nattKeepalivePacket KeepalivePacketData(InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort, byte[] data)61 protected KeepalivePacketData(InetAddress srcAddress, int srcPort, 62 InetAddress dstAddress, int dstPort, byte[] data) throws InvalidPacketException { 63 this.srcAddress = srcAddress; 64 this.dstAddress = dstAddress; 65 this.srcPort = srcPort; 66 this.dstPort = dstPort; 67 this.mPacket = data; 68 69 // Check we have two IP addresses of the same family. 70 if (srcAddress == null || dstAddress == null || !srcAddress.getClass().getName() 71 .equals(dstAddress.getClass().getName())) { 72 Log.e(TAG, "Invalid or mismatched InetAddresses in KeepalivePacketData"); 73 throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS); 74 } 75 76 // Check the ports. 77 if (!IpUtils.isValidUdpOrTcpPort(srcPort) || !IpUtils.isValidUdpOrTcpPort(dstPort)) { 78 Log.e(TAG, "Invalid ports in KeepalivePacketData"); 79 throw new InvalidPacketException(ERROR_INVALID_PORT); 80 } 81 } 82 83 public static class InvalidPacketException extends Exception { 84 public final int error; InvalidPacketException(int error)85 public InvalidPacketException(int error) { 86 this.error = error; 87 } 88 } 89 getPacket()90 public byte[] getPacket() { 91 return mPacket.clone(); 92 } 93 nattKeepalivePacket( InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort)94 public static KeepalivePacketData nattKeepalivePacket( 95 InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort) 96 throws InvalidPacketException { 97 98 if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) { 99 throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS); 100 } 101 102 if (dstPort != NATT_PORT) { 103 throw new InvalidPacketException(ERROR_INVALID_PORT); 104 } 105 106 int length = IPV4_HEADER_LENGTH + UDP_HEADER_LENGTH + 1; 107 ByteBuffer buf = ByteBuffer.allocate(length); 108 buf.order(ByteOrder.BIG_ENDIAN); 109 buf.putShort((short) 0x4500); // IP version and TOS 110 buf.putShort((short) length); 111 buf.putInt(0); // ID, flags, offset 112 buf.put((byte) 64); // TTL 113 buf.put((byte) OsConstants.IPPROTO_UDP); 114 int ipChecksumOffset = buf.position(); 115 buf.putShort((short) 0); // IP checksum 116 buf.put(srcAddress.getAddress()); 117 buf.put(dstAddress.getAddress()); 118 buf.putShort((short) srcPort); 119 buf.putShort((short) dstPort); 120 buf.putShort((short) (length - 20)); // UDP length 121 int udpChecksumOffset = buf.position(); 122 buf.putShort((short) 0); // UDP checksum 123 buf.put((byte) 0xff); // NAT-T keepalive 124 buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0)); 125 buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_LENGTH)); 126 127 return new KeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array()); 128 } 129 130 /* Parcelable Implementation */ describeContents()131 public int describeContents() { 132 return 0; 133 } 134 135 /** Write to parcel */ writeToParcel(Parcel out, int flags)136 public void writeToParcel(Parcel out, int flags) { 137 out.writeString(srcAddress.getHostAddress()); 138 out.writeString(dstAddress.getHostAddress()); 139 out.writeInt(srcPort); 140 out.writeInt(dstPort); 141 out.writeByteArray(mPacket); 142 } 143 KeepalivePacketData(Parcel in)144 private KeepalivePacketData(Parcel in) { 145 srcAddress = NetworkUtils.numericToInetAddress(in.readString()); 146 dstAddress = NetworkUtils.numericToInetAddress(in.readString()); 147 srcPort = in.readInt(); 148 dstPort = in.readInt(); 149 mPacket = in.createByteArray(); 150 } 151 152 /** Parcelable Creator */ 153 public static final Parcelable.Creator<KeepalivePacketData> CREATOR = 154 new Parcelable.Creator<KeepalivePacketData>() { 155 public KeepalivePacketData createFromParcel(Parcel in) { 156 return new KeepalivePacketData(in); 157 } 158 159 public KeepalivePacketData[] newArray(int size) { 160 return new KeepalivePacketData[size]; 161 } 162 }; 163 164 } 165