1 /*
2  * Copyright (C) 2015 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;
18 
19 import static android.net.ConnectivityManager.PacketKeepalive.*;
20 
21 import android.net.util.IpUtils;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.system.OsConstants;
25 import android.util.Log;
26 
27 import java.net.Inet4Address;
28 import java.net.InetAddress;
29 import java.nio.ByteBuffer;
30 import java.nio.ByteOrder;
31 
32 /**
33  * Represents the actual packets that are sent by the
34  * {@link android.net.ConnectivityManager.PacketKeepalive} API.
35  *
36  * @hide
37  */
38 public class KeepalivePacketData implements Parcelable {
39     private static final String TAG = "KeepalivePacketData";
40 
41     /** Source IP address */
42     public final InetAddress srcAddress;
43 
44     /** Destination IP address */
45     public final InetAddress dstAddress;
46 
47     /** Source port */
48     public final int srcPort;
49 
50     /** Destination port */
51     public final int dstPort;
52 
53     /** Packet data. A raw byte string of packet data, not including the link-layer header. */
54     private final byte[] mPacket;
55 
56     private static final int IPV4_HEADER_LENGTH = 20;
57     private static final int UDP_HEADER_LENGTH = 8;
58 
59     // This should only be constructed via static factory methods, such as
60     // nattKeepalivePacket
KeepalivePacketData(InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort, byte[] data)61     protected KeepalivePacketData(InetAddress srcAddress, int srcPort,
62             InetAddress dstAddress, int dstPort, byte[] data) throws InvalidPacketException {
63         this.srcAddress = srcAddress;
64         this.dstAddress = dstAddress;
65         this.srcPort = srcPort;
66         this.dstPort = dstPort;
67         this.mPacket = data;
68 
69         // Check we have two IP addresses of the same family.
70         if (srcAddress == null || dstAddress == null || !srcAddress.getClass().getName()
71                 .equals(dstAddress.getClass().getName())) {
72             Log.e(TAG, "Invalid or mismatched InetAddresses in KeepalivePacketData");
73             throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
74         }
75 
76         // Check the ports.
77         if (!IpUtils.isValidUdpOrTcpPort(srcPort) || !IpUtils.isValidUdpOrTcpPort(dstPort)) {
78             Log.e(TAG, "Invalid ports in KeepalivePacketData");
79             throw new InvalidPacketException(ERROR_INVALID_PORT);
80         }
81     }
82 
83     public static class InvalidPacketException extends Exception {
84         public final int error;
InvalidPacketException(int error)85         public InvalidPacketException(int error) {
86             this.error = error;
87         }
88     }
89 
getPacket()90     public byte[] getPacket() {
91         return mPacket.clone();
92     }
93 
nattKeepalivePacket( InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort)94     public static KeepalivePacketData nattKeepalivePacket(
95             InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort)
96             throws InvalidPacketException {
97 
98         if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) {
99             throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
100         }
101 
102         if (dstPort != NATT_PORT) {
103             throw new InvalidPacketException(ERROR_INVALID_PORT);
104         }
105 
106         int length = IPV4_HEADER_LENGTH + UDP_HEADER_LENGTH + 1;
107         ByteBuffer buf = ByteBuffer.allocate(length);
108         buf.order(ByteOrder.BIG_ENDIAN);
109         buf.putShort((short) 0x4500);             // IP version and TOS
110         buf.putShort((short) length);
111         buf.putInt(0);                            // ID, flags, offset
112         buf.put((byte) 64);                       // TTL
113         buf.put((byte) OsConstants.IPPROTO_UDP);
114         int ipChecksumOffset = buf.position();
115         buf.putShort((short) 0);                  // IP checksum
116         buf.put(srcAddress.getAddress());
117         buf.put(dstAddress.getAddress());
118         buf.putShort((short) srcPort);
119         buf.putShort((short) dstPort);
120         buf.putShort((short) (length - 20));      // UDP length
121         int udpChecksumOffset = buf.position();
122         buf.putShort((short) 0);                  // UDP checksum
123         buf.put((byte) 0xff);                     // NAT-T keepalive
124         buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0));
125         buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_LENGTH));
126 
127         return new KeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array());
128     }
129 
130     /* Parcelable Implementation */
describeContents()131     public int describeContents() {
132         return 0;
133     }
134 
135     /** Write to parcel */
writeToParcel(Parcel out, int flags)136     public void writeToParcel(Parcel out, int flags) {
137         out.writeString(srcAddress.getHostAddress());
138         out.writeString(dstAddress.getHostAddress());
139         out.writeInt(srcPort);
140         out.writeInt(dstPort);
141         out.writeByteArray(mPacket);
142     }
143 
KeepalivePacketData(Parcel in)144     private KeepalivePacketData(Parcel in) {
145         srcAddress = NetworkUtils.numericToInetAddress(in.readString());
146         dstAddress = NetworkUtils.numericToInetAddress(in.readString());
147         srcPort = in.readInt();
148         dstPort = in.readInt();
149         mPacket = in.createByteArray();
150     }
151 
152     /** Parcelable Creator */
153     public static final Parcelable.Creator<KeepalivePacketData> CREATOR =
154             new Parcelable.Creator<KeepalivePacketData>() {
155                 public KeepalivePacketData createFromParcel(Parcel in) {
156                     return new KeepalivePacketData(in);
157                 }
158 
159                 public KeepalivePacketData[] newArray(int size) {
160                     return new KeepalivePacketData[size];
161                 }
162             };
163 
164 }
165