blob: 3fb52f12a88dfbf5c19b5c6c19232405c563308a [file] [log] [blame]
junyulai06835112019-01-03 18:50:15 +08001/*
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
17package android.net;
18
markchien150e1912018-12-27 22:49:51 +080019import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
20import static android.net.SocketKeepalive.ERROR_INVALID_PORT;
21
junyulai06835112019-01-03 18:50:15 +080022import android.net.util.IpUtils;
junyulai02abbfd2019-06-03 17:51:41 +080023import android.os.Parcel;
Aaron Huang76985bd2019-04-23 22:17:16 +080024import android.os.Parcelable;
junyulai06835112019-01-03 18:50:15 +080025import android.system.OsConstants;
26
27import java.net.Inet4Address;
28import java.net.InetAddress;
29import java.nio.ByteBuffer;
30import java.nio.ByteOrder;
31
32/** @hide */
Aaron Huang76985bd2019-04-23 22:17:16 +080033public final class NattKeepalivePacketData extends KeepalivePacketData implements Parcelable {
Aaron Huang08d9ade2019-10-02 01:39:46 +080034 private static final int IPV4_HEADER_LENGTH = 20;
35 private static final int UDP_HEADER_LENGTH = 8;
36
junyulai06835112019-01-03 18:50:15 +080037 // This should only be constructed via static factory methods, such as
38 // nattKeepalivePacket
39 private NattKeepalivePacketData(InetAddress srcAddress, int srcPort,
40 InetAddress dstAddress, int dstPort, byte[] data) throws
41 InvalidPacketException {
42 super(srcAddress, srcPort, dstAddress, dstPort, data);
43 }
44
45 /**
46 * Factory method to create Nat-T keepalive packet structure.
47 */
48 public static NattKeepalivePacketData nattKeepalivePacket(
49 InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort)
50 throws InvalidPacketException {
51
52 if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) {
markchien150e1912018-12-27 22:49:51 +080053 throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
junyulai06835112019-01-03 18:50:15 +080054 }
55
56 if (dstPort != NattSocketKeepalive.NATT_PORT) {
markchien150e1912018-12-27 22:49:51 +080057 throw new InvalidPacketException(ERROR_INVALID_PORT);
junyulai06835112019-01-03 18:50:15 +080058 }
59
60 int length = IPV4_HEADER_LENGTH + UDP_HEADER_LENGTH + 1;
61 ByteBuffer buf = ByteBuffer.allocate(length);
62 buf.order(ByteOrder.BIG_ENDIAN);
63 buf.putShort((short) 0x4500); // IP version and TOS
64 buf.putShort((short) length);
65 buf.putInt(0); // ID, flags, offset
66 buf.put((byte) 64); // TTL
67 buf.put((byte) OsConstants.IPPROTO_UDP);
68 int ipChecksumOffset = buf.position();
69 buf.putShort((short) 0); // IP checksum
70 buf.put(srcAddress.getAddress());
71 buf.put(dstAddress.getAddress());
72 buf.putShort((short) srcPort);
73 buf.putShort((short) dstPort);
74 buf.putShort((short) (length - 20)); // UDP length
75 int udpChecksumOffset = buf.position();
76 buf.putShort((short) 0); // UDP checksum
77 buf.put((byte) 0xff); // NAT-T keepalive
78 buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0));
79 buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_LENGTH));
80
81 return new NattKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array());
82 }
Aaron Huang76985bd2019-04-23 22:17:16 +080083
junyulai02abbfd2019-06-03 17:51:41 +080084 /** Parcelable Implementation */
85 public int describeContents() {
86 return 0;
Aaron Huang76985bd2019-04-23 22:17:16 +080087 }
junyulai02abbfd2019-06-03 17:51:41 +080088
89 /** Write to parcel */
90 public void writeToParcel(Parcel out, int flags) {
91 out.writeString(srcAddress.getHostAddress());
92 out.writeString(dstAddress.getHostAddress());
93 out.writeInt(srcPort);
94 out.writeInt(dstPort);
95 }
96
97 /** Parcelable Creator */
98 public static final Parcelable.Creator<NattKeepalivePacketData> CREATOR =
99 new Parcelable.Creator<NattKeepalivePacketData>() {
100 public NattKeepalivePacketData createFromParcel(Parcel in) {
101 final InetAddress srcAddress =
102 InetAddresses.parseNumericAddress(in.readString());
103 final InetAddress dstAddress =
104 InetAddresses.parseNumericAddress(in.readString());
105 final int srcPort = in.readInt();
106 final int dstPort = in.readInt();
107 try {
108 return NattKeepalivePacketData.nattKeepalivePacket(srcAddress, srcPort,
109 dstAddress, dstPort);
110 } catch (InvalidPacketException e) {
111 throw new IllegalArgumentException(
112 "Invalid NAT-T keepalive data: " + e.error);
113 }
114 }
115
116 public NattKeepalivePacketData[] newArray(int size) {
117 return new NattKeepalivePacketData[size];
118 }
119 };
junyulai06835112019-01-03 18:50:15 +0800120}