1 /* 2 * Copyright (C) 2023 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 com.android.internal.annotations.VisibleForTesting.Visibility; 19 20 import android.annotation.FlaggedApi; 21 import android.annotation.NonNull; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 import android.os.SystemClock; 25 26 import com.android.internal.annotations.VisibleForTesting; 27 import com.android.net.flags.Flags; 28 import com.android.net.module.util.HexDump; 29 30 import java.util.Objects; 31 32 /** 33 * This class represents a snapshot of the state of an IpSecTransform 34 * 35 * <p>This class provides the current state of an IpSecTransform, enabling link metric analysis by 36 * the caller. Use cases include understanding transform usage, such as packet and byte counts, as 37 * well as observing out-of-order delivery by checking the bitmap. Additionally, callers can query 38 * IpSecTransformStates at two timestamps. By comparing the changes in packet counts and sequence 39 * numbers, callers can estimate IPsec data loss in the inbound direction. 40 */ 41 @FlaggedApi(Flags.FLAG_IPSEC_TRANSFORM_STATE) 42 public final class IpSecTransformState implements Parcelable { 43 private final long mTimestamp; 44 private final long mTxHighestSequenceNumber; 45 private final long mRxHighestSequenceNumber; 46 private final long mPacketCount; 47 private final long mByteCount; 48 private final byte[] mReplayBitmap; 49 IpSecTransformState( long timestamp, long txHighestSequenceNumber, long rxHighestSequenceNumber, long packetCount, long byteCount, byte[] replayBitmap)50 private IpSecTransformState( 51 long timestamp, 52 long txHighestSequenceNumber, 53 long rxHighestSequenceNumber, 54 long packetCount, 55 long byteCount, 56 byte[] replayBitmap) { 57 mTimestamp = timestamp; 58 mTxHighestSequenceNumber = txHighestSequenceNumber; 59 mRxHighestSequenceNumber = rxHighestSequenceNumber; 60 mPacketCount = packetCount; 61 mByteCount = byteCount; 62 63 Objects.requireNonNull(replayBitmap, "replayBitmap is null"); 64 mReplayBitmap = replayBitmap.clone(); 65 66 validate(); 67 } 68 validate()69 private void validate() { 70 Objects.requireNonNull(mReplayBitmap, "mReplayBitmap is null"); 71 } 72 73 /** 74 * Deserializes a IpSecTransformState from a PersistableBundle. 75 * 76 * @hide 77 */ 78 @VisibleForTesting(visibility = Visibility.PRIVATE) IpSecTransformState(@onNull Parcel in)79 public IpSecTransformState(@NonNull Parcel in) { 80 Objects.requireNonNull(in, "The input PersistableBundle is null"); 81 mTimestamp = in.readLong(); 82 mTxHighestSequenceNumber = in.readLong(); 83 mRxHighestSequenceNumber = in.readLong(); 84 mPacketCount = in.readLong(); 85 mByteCount = in.readLong(); 86 mReplayBitmap = HexDump.hexStringToByteArray(in.readString()); 87 88 validate(); 89 } 90 91 // Parcelable methods 92 93 @Override describeContents()94 public int describeContents() { 95 return 0; 96 } 97 98 @Override writeToParcel(@onNull Parcel out, int flags)99 public void writeToParcel(@NonNull Parcel out, int flags) { 100 out.writeLong(mTimestamp); 101 out.writeLong(mTxHighestSequenceNumber); 102 out.writeLong(mRxHighestSequenceNumber); 103 out.writeLong(mPacketCount); 104 out.writeLong(mByteCount); 105 out.writeString(HexDump.toHexString(mReplayBitmap)); 106 } 107 108 @NonNull 109 public static final Parcelable.Creator<IpSecTransformState> CREATOR = 110 new Parcelable.Creator<IpSecTransformState>() { 111 @NonNull 112 public IpSecTransformState createFromParcel(Parcel in) { 113 return new IpSecTransformState(in); 114 } 115 116 @NonNull 117 public IpSecTransformState[] newArray(int size) { 118 return new IpSecTransformState[size]; 119 } 120 }; 121 122 /** 123 * Retrieve the timestamp (milliseconds) when this state was created, as per {@link 124 * SystemClock#elapsedRealtime} 125 * 126 * @see Builder#setTimestampMillis(long) 127 */ getTimestampMillis()128 public long getTimestampMillis() { 129 return mTimestamp; 130 } 131 132 /** 133 * Retrieve the highest sequence number sent so far as an unsigned long 134 * 135 * @see Builder#setTxHighestSequenceNumber(long) 136 */ getTxHighestSequenceNumber()137 public long getTxHighestSequenceNumber() { 138 return mTxHighestSequenceNumber; 139 } 140 141 /** 142 * Retrieve the highest sequence number received so far as an unsigned long 143 * 144 * @see Builder#setRxHighestSequenceNumber(long) 145 */ getRxHighestSequenceNumber()146 public long getRxHighestSequenceNumber() { 147 return mRxHighestSequenceNumber; 148 } 149 150 /** 151 * Retrieve the number of packets processed so far as an unsigned long. 152 * 153 * <p>The packet count direction (inbound or outbound) aligns with the direction in which the 154 * IpSecTransform is applied to. 155 * 156 * @see Builder#setPacketCount(long) 157 */ getPacketCount()158 public long getPacketCount() { 159 return mPacketCount; 160 } 161 162 /** 163 * Retrieve the number of bytes processed so far as an unsigned long 164 * 165 * <p>The byte count direction (inbound or outbound) aligns with the direction in which the 166 * IpSecTransform is applied to. 167 * 168 * @see Builder#setByteCount(long) 169 */ getByteCount()170 public long getByteCount() { 171 return mByteCount; 172 } 173 174 /** 175 * Retrieve the replay bitmap 176 * 177 * <p>This bitmap represents a replay window, allowing the caller to observe out-of-order 178 * delivery. The last bit represents the highest sequence number received so far and bits for 179 * the received packets will be marked as true. 180 * 181 * <p>The size of a replay bitmap will never change over the lifetime of an IpSecTransform 182 * 183 * <p>The replay bitmap is solely useful for inbound IpSecTransforms. For outbound 184 * IpSecTransforms, all bits will be unchecked. 185 * 186 * @see Builder#setReplayBitmap(byte[]) 187 */ 188 @NonNull getReplayBitmap()189 public byte[] getReplayBitmap() { 190 return mReplayBitmap.clone(); 191 } 192 193 /** 194 * Builder class for testing purposes 195 * 196 * <p>Except for testing, IPsec callers normally do not instantiate {@link IpSecTransformState} 197 * themselves but instead get a reference via {@link IpSecTransformState} 198 */ 199 @FlaggedApi(Flags.FLAG_IPSEC_TRANSFORM_STATE) 200 public static final class Builder { 201 private long mTimestamp; 202 private long mTxHighestSequenceNumber; 203 private long mRxHighestSequenceNumber; 204 private long mPacketCount; 205 private long mByteCount; 206 private byte[] mReplayBitmap; 207 Builder()208 public Builder() { 209 mTimestamp = SystemClock.elapsedRealtime(); 210 } 211 212 /** 213 * Set the timestamp (milliseconds) when this state was created 214 * 215 * @see IpSecTransformState#getTimestampMillis() 216 */ 217 @NonNull setTimestampMillis(long timestamp)218 public Builder setTimestampMillis(long timestamp) { 219 mTimestamp = timestamp; 220 return this; 221 } 222 223 /** 224 * Set the highest sequence number sent so far as an unsigned long 225 * 226 * @see IpSecTransformState#getTxHighestSequenceNumber() 227 */ 228 @NonNull setTxHighestSequenceNumber(long seqNum)229 public Builder setTxHighestSequenceNumber(long seqNum) { 230 mTxHighestSequenceNumber = seqNum; 231 return this; 232 } 233 234 /** 235 * Set the highest sequence number received so far as an unsigned long 236 * 237 * @see IpSecTransformState#getRxHighestSequenceNumber() 238 */ 239 @NonNull setRxHighestSequenceNumber(long seqNum)240 public Builder setRxHighestSequenceNumber(long seqNum) { 241 mRxHighestSequenceNumber = seqNum; 242 return this; 243 } 244 245 /** 246 * Set the number of packets processed so far as an unsigned long 247 * 248 * @see IpSecTransformState#getPacketCount() 249 */ 250 @NonNull setPacketCount(long packetCount)251 public Builder setPacketCount(long packetCount) { 252 mPacketCount = packetCount; 253 return this; 254 } 255 256 /** 257 * Set the number of bytes processed so far as an unsigned long 258 * 259 * @see IpSecTransformState#getByteCount() 260 */ 261 @NonNull setByteCount(long byteCount)262 public Builder setByteCount(long byteCount) { 263 mByteCount = byteCount; 264 return this; 265 } 266 267 /** 268 * Set the replay bitmap 269 * 270 * @see IpSecTransformState#getReplayBitmap() 271 */ 272 @NonNull setReplayBitmap(@onNull byte[] bitMap)273 public Builder setReplayBitmap(@NonNull byte[] bitMap) { 274 mReplayBitmap = bitMap.clone(); 275 return this; 276 } 277 278 /** 279 * Build and validate the IpSecTransformState 280 * 281 * @return an immutable IpSecTransformState instance 282 */ 283 @NonNull build()284 public IpSecTransformState build() { 285 return new IpSecTransformState( 286 mTimestamp, 287 mTxHighestSequenceNumber, 288 mRxHighestSequenceNumber, 289 mPacketCount, 290 mByteCount, 291 mReplayBitmap); 292 } 293 } 294 } 295