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