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 
17 package android.net.util;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.net.KeepalivePacketData;
22 import android.net.NattKeepalivePacketData;
23 import android.net.NattKeepalivePacketDataParcelable;
24 import android.net.TcpKeepalivePacketData;
25 import android.net.TcpKeepalivePacketDataParcelable;
26 import android.os.Build;
27 import android.util.Log;
28 
29 import java.net.InetAddress;
30 import java.nio.ByteBuffer;
31 import java.nio.ByteOrder;
32 
33 /**
34  * Utility class to convert to/from keepalive data parcelables.
35  *
36  * TODO: move to networkstack-client library when it is moved to frameworks/libs/net.
37  * This class cannot go into other shared libraries as it depends on NetworkStack AIDLs.
38  * @hide
39  */
40 public final class KeepalivePacketDataUtil {
41     private static final int IPV4_HEADER_LENGTH = 20;
42     private static final int IPV6_HEADER_LENGTH = 40;
43 
44     private static final String TAG = KeepalivePacketDataUtil.class.getSimpleName();
45 
46     /**
47      * Convert a NattKeepalivePacketData to a NattKeepalivePacketDataParcelable.
48      */
49     @NonNull
toStableParcelable( @onNull NattKeepalivePacketData pkt)50     public static NattKeepalivePacketDataParcelable toStableParcelable(
51             @NonNull NattKeepalivePacketData pkt) {
52         final NattKeepalivePacketDataParcelable parcel = new NattKeepalivePacketDataParcelable();
53         final InetAddress srcAddress = pkt.getSrcAddress();
54         final InetAddress dstAddress = pkt.getDstAddress();
55         parcel.srcAddress = srcAddress.getAddress();
56         parcel.srcPort = pkt.getSrcPort();
57         parcel.dstAddress = dstAddress.getAddress();
58         parcel.dstPort = pkt.getDstPort();
59         return parcel;
60     }
61 
62     /**
63      * Convert a TcpKeepalivePacketData to a TcpKeepalivePacketDataParcelable.
64      */
65     @NonNull
toStableParcelable( @onNull TcpKeepalivePacketData pkt)66     public static TcpKeepalivePacketDataParcelable toStableParcelable(
67             @NonNull TcpKeepalivePacketData pkt) {
68         final TcpKeepalivePacketDataParcelable parcel = new TcpKeepalivePacketDataParcelable();
69         final InetAddress srcAddress = pkt.getSrcAddress();
70         final InetAddress dstAddress = pkt.getDstAddress();
71         parcel.srcAddress = srcAddress.getAddress();
72         parcel.srcPort = pkt.getSrcPort();
73         parcel.dstAddress = dstAddress.getAddress();
74         parcel.dstPort = pkt.getDstPort();
75         parcel.seq = pkt.getTcpSeq();
76         parcel.ack = pkt.getTcpAck();
77         parcel.rcvWnd = pkt.getTcpWindow();
78         parcel.rcvWndScale = pkt.getTcpWindowScale();
79         parcel.tos = pkt.getIpTos();
80         parcel.ttl = pkt.getIpTtl();
81         return parcel;
82     }
83 
84     // TODO: add buildV6Packet.
85 
86     /**
87      * Get a {@link TcpKeepalivePacketDataParcelable} from {@link KeepalivePacketData}, if the
88      * generic class actually contains TCP keepalive data.
89      *
90      * @deprecated This method is used on R platforms where android.net.TcpKeepalivePacketData was
91      * not yet system API. Newer platforms should use android.net.TcpKeepalivePacketData directly.
92      *
93      * @param data A {@link KeepalivePacketData} that may contain TCP keepalive data.
94      * @return A parcelable containing TCP keepalive data, or null if the input data does not
95      *         contain TCP keepalive data.
96      */
97     @Deprecated
98     @SuppressWarnings("AndroidFrameworkCompatChange") // API version check used to Log.wtf
99     @Nullable
parseTcpKeepalivePacketData( @ullable KeepalivePacketData data)100     public static TcpKeepalivePacketDataParcelable parseTcpKeepalivePacketData(
101             @Nullable KeepalivePacketData data) {
102         if (data == null) return null;
103 
104         if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
105             Log.wtf(TAG, "parseTcpKeepalivePacketData should not be used after R, use "
106                     + "TcpKeepalivePacketData instead.");
107         }
108 
109         // Reconstruct TcpKeepalivePacketData from the packet contained in KeepalivePacketData
110         final ByteBuffer buffer = ByteBuffer.wrap(data.getPacket());
111         buffer.order(ByteOrder.BIG_ENDIAN);
112 
113         // Most of the fields are accessible from the KeepalivePacketData superclass: instead of
114         // using Struct to parse everything, just extract the extra fields necessary for
115         // TcpKeepalivePacketData.
116         final int tcpSeq;
117         final int tcpAck;
118         final int wndSize;
119         final int ipTos;
120         final int ttl;
121         try {
122             // This only support IPv4, because TcpKeepalivePacketData only supports IPv4 for R and
123             // below, and this method should not be used on newer platforms.
124             tcpSeq = buffer.getInt(IPV4_HEADER_LENGTH + 4);
125             tcpAck = buffer.getInt(IPV4_HEADER_LENGTH + 8);
126             wndSize = buffer.getShort(IPV4_HEADER_LENGTH + 14);
127             ipTos = buffer.get(1);
128             ttl = buffer.get(8);
129         } catch (IndexOutOfBoundsException e) {
130             return null;
131         }
132 
133         final TcpKeepalivePacketDataParcelable p = new TcpKeepalivePacketDataParcelable();
134         p.srcAddress = data.getSrcAddress().getAddress();
135         p.srcPort = data.getSrcPort();
136         p.dstAddress = data.getDstAddress().getAddress();
137         p.dstPort = data.getDstPort();
138         p.seq = tcpSeq;
139         p.ack = tcpAck;
140         // TcpKeepalivePacketData could actually use non-zero wndScale, but this does not affect
141         // actual functionality as generated packets will be the same (no wndScale option added)
142         p.rcvWnd = wndSize;
143         p.rcvWndScale = 0;
144         p.tos = ipTos;
145         p.ttl = ttl;
146         return p;
147     }
148 }
149