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