1 /* 2 * Copyright (C) 2019 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 package android.net; 17 18 import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS; 19 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.net.SocketKeepalive.InvalidPacketException; 23 import android.net.util.IpUtils; 24 import android.os.Parcel; 25 import android.os.Parcelable; 26 import android.system.OsConstants; 27 28 import java.net.InetAddress; 29 import java.net.UnknownHostException; 30 import java.nio.ByteBuffer; 31 import java.nio.ByteOrder; 32 import java.util.Objects; 33 34 /** 35 * Represents the actual tcp keep alive packets which will be used for hardware offload. 36 * @hide 37 */ 38 public class TcpKeepalivePacketData extends KeepalivePacketData implements Parcelable { 39 private static final String TAG = "TcpKeepalivePacketData"; 40 41 /** TCP sequence number. */ 42 public final int tcpSeq; 43 44 /** TCP ACK number. */ 45 public final int tcpAck; 46 47 /** TCP RCV window. */ 48 public final int tcpWnd; 49 50 /** TCP RCV window scale. */ 51 public final int tcpWndScale; 52 53 /** IP TOS. */ 54 public final int ipTos; 55 56 /** IP TTL. */ 57 public final int ipTtl; 58 59 private static final int IPV4_HEADER_LENGTH = 20; 60 private static final int IPV6_HEADER_LENGTH = 40; 61 private static final int TCP_HEADER_LENGTH = 20; 62 63 // This should only be constructed via static factory methods, such as 64 // tcpKeepalivePacket. TcpKeepalivePacketData(final TcpKeepalivePacketDataParcelable tcpDetails, final byte[] data)65 private TcpKeepalivePacketData(final TcpKeepalivePacketDataParcelable tcpDetails, 66 final byte[] data) throws InvalidPacketException, UnknownHostException { 67 super(InetAddress.getByAddress(tcpDetails.srcAddress), tcpDetails.srcPort, 68 InetAddress.getByAddress(tcpDetails.dstAddress), tcpDetails.dstPort, data); 69 tcpSeq = tcpDetails.seq; 70 tcpAck = tcpDetails.ack; 71 // In the packet, the window is shifted right by the window scale. 72 tcpWnd = tcpDetails.rcvWnd; 73 tcpWndScale = tcpDetails.rcvWndScale; 74 ipTos = tcpDetails.tos; 75 ipTtl = tcpDetails.ttl; 76 } 77 78 /** 79 * Factory method to create tcp keepalive packet structure. 80 */ tcpKeepalivePacket( TcpKeepalivePacketDataParcelable tcpDetails)81 public static TcpKeepalivePacketData tcpKeepalivePacket( 82 TcpKeepalivePacketDataParcelable tcpDetails) throws InvalidPacketException { 83 final byte[] packet; 84 try { 85 if ((tcpDetails.srcAddress != null) && (tcpDetails.dstAddress != null) 86 && (tcpDetails.srcAddress.length == 4 /* V4 IP length */) 87 && (tcpDetails.dstAddress.length == 4 /* V4 IP length */)) { 88 packet = buildV4Packet(tcpDetails); 89 } else { 90 // TODO: support ipv6 91 throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS); 92 } 93 return new TcpKeepalivePacketData(tcpDetails, packet); 94 } catch (UnknownHostException e) { 95 throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS); 96 } 97 98 } 99 100 /** 101 * Build ipv4 tcp keepalive packet, not including the link-layer header. 102 */ 103 // TODO : if this code is ever moved to the network stack, factorize constants with the ones 104 // over there. buildV4Packet(TcpKeepalivePacketDataParcelable tcpDetails)105 private static byte[] buildV4Packet(TcpKeepalivePacketDataParcelable tcpDetails) { 106 final int length = IPV4_HEADER_LENGTH + TCP_HEADER_LENGTH; 107 ByteBuffer buf = ByteBuffer.allocate(length); 108 buf.order(ByteOrder.BIG_ENDIAN); 109 buf.put((byte) 0x45); // IP version and IHL 110 buf.put((byte) tcpDetails.tos); // TOS 111 buf.putShort((short) length); 112 buf.putInt(0x00004000); // ID, flags=DF, offset 113 buf.put((byte) tcpDetails.ttl); // TTL 114 buf.put((byte) OsConstants.IPPROTO_TCP); 115 final int ipChecksumOffset = buf.position(); 116 buf.putShort((short) 0); // IP checksum 117 buf.put(tcpDetails.srcAddress); 118 buf.put(tcpDetails.dstAddress); 119 buf.putShort((short) tcpDetails.srcPort); 120 buf.putShort((short) tcpDetails.dstPort); 121 buf.putInt(tcpDetails.seq); // Sequence Number 122 buf.putInt(tcpDetails.ack); // ACK 123 buf.putShort((short) 0x5010); // TCP length=5, flags=ACK 124 buf.putShort((short) (tcpDetails.rcvWnd >> tcpDetails.rcvWndScale)); // Window size 125 final int tcpChecksumOffset = buf.position(); 126 buf.putShort((short) 0); // TCP checksum 127 // URG is not set therefore the urgent pointer is zero. 128 buf.putShort((short) 0); // Urgent pointer 129 130 buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0)); 131 buf.putShort(tcpChecksumOffset, IpUtils.tcpChecksum( 132 buf, 0, IPV4_HEADER_LENGTH, TCP_HEADER_LENGTH)); 133 134 return buf.array(); 135 } 136 137 // TODO: add buildV6Packet. 138 139 @Override equals(@ullable final Object o)140 public boolean equals(@Nullable final Object o) { 141 if (!(o instanceof TcpKeepalivePacketData)) return false; 142 final TcpKeepalivePacketData other = (TcpKeepalivePacketData) o; 143 return this.srcAddress.equals(other.srcAddress) 144 && this.dstAddress.equals(other.dstAddress) 145 && this.srcPort == other.srcPort 146 && this.dstPort == other.dstPort 147 && this.tcpAck == other.tcpAck 148 && this.tcpSeq == other.tcpSeq 149 && this.tcpWnd == other.tcpWnd 150 && this.tcpWndScale == other.tcpWndScale 151 && this.ipTos == other.ipTos 152 && this.ipTtl == other.ipTtl; 153 } 154 155 @Override hashCode()156 public int hashCode() { 157 return Objects.hash(srcAddress, dstAddress, srcPort, dstPort, tcpAck, tcpSeq, tcpWnd, 158 tcpWndScale, ipTos, ipTtl); 159 } 160 161 /** 162 * Parcelable Implementation. 163 * Note that this object implements parcelable (and needs to keep doing this as it inherits 164 * from a class that does), but should usually be parceled as a stable parcelable using 165 * the toStableParcelable() and fromStableParcelable() methods. 166 */ describeContents()167 public int describeContents() { 168 return 0; 169 } 170 171 /** Write to parcel. */ writeToParcel(Parcel out, int flags)172 public void writeToParcel(Parcel out, int flags) { 173 super.writeToParcel(out, flags); 174 out.writeInt(tcpSeq); 175 out.writeInt(tcpAck); 176 out.writeInt(tcpWnd); 177 out.writeInt(tcpWndScale); 178 out.writeInt(ipTos); 179 out.writeInt(ipTtl); 180 } 181 TcpKeepalivePacketData(Parcel in)182 private TcpKeepalivePacketData(Parcel in) { 183 super(in); 184 tcpSeq = in.readInt(); 185 tcpAck = in.readInt(); 186 tcpWnd = in.readInt(); 187 tcpWndScale = in.readInt(); 188 ipTos = in.readInt(); 189 ipTtl = in.readInt(); 190 } 191 192 /** Parcelable Creator. */ 193 public static final @NonNull Parcelable.Creator<TcpKeepalivePacketData> CREATOR = 194 new Parcelable.Creator<TcpKeepalivePacketData>() { 195 public TcpKeepalivePacketData createFromParcel(Parcel in) { 196 return new TcpKeepalivePacketData(in); 197 } 198 199 public TcpKeepalivePacketData[] newArray(int size) { 200 return new TcpKeepalivePacketData[size]; 201 } 202 }; 203 204 /** 205 * Convert this TcpKeepalivePacketData to a TcpKeepalivePacketDataParcelable. 206 */ 207 @NonNull toStableParcelable()208 public TcpKeepalivePacketDataParcelable toStableParcelable() { 209 final TcpKeepalivePacketDataParcelable parcel = new TcpKeepalivePacketDataParcelable(); 210 parcel.srcAddress = srcAddress.getAddress(); 211 parcel.srcPort = srcPort; 212 parcel.dstAddress = dstAddress.getAddress(); 213 parcel.dstPort = dstPort; 214 parcel.seq = tcpSeq; 215 parcel.ack = tcpAck; 216 parcel.rcvWnd = tcpWnd; 217 parcel.rcvWndScale = tcpWndScale; 218 parcel.tos = ipTos; 219 parcel.ttl = ipTtl; 220 return parcel; 221 } 222 223 @Override toString()224 public String toString() { 225 return "saddr: " + srcAddress 226 + " daddr: " + dstAddress 227 + " sport: " + srcPort 228 + " dport: " + dstPort 229 + " seq: " + tcpSeq 230 + " ack: " + tcpAck 231 + " wnd: " + tcpWnd 232 + " wndScale: " + tcpWndScale 233 + " tos: " + ipTos 234 + " ttl: " + ipTtl; 235 } 236 } 237