blob: 22288b6205d7712afdfac44ef2e641ca968d9d94 [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
Aaron Huang8e5e8c92020-01-09 22:04:21 +080019import static android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS;
20import static android.net.InvalidPacketException.ERROR_INVALID_PORT;
markchien150e1912018-12-27 22:49:51 +080021
Aaron Huang8e5e8c92020-01-09 22:04:21 +080022import android.annotation.NonNull;
Chiachang Wangd4d035d2020-03-13 16:37:04 +080023import android.annotation.Nullable;
Aaron Huang8e5e8c92020-01-09 22:04:21 +080024import android.annotation.SystemApi;
junyulai06835112019-01-03 18:50:15 +080025import android.net.util.IpUtils;
junyulai02abbfd2019-06-03 17:51:41 +080026import android.os.Parcel;
Aaron Huang76985bd2019-04-23 22:17:16 +080027import android.os.Parcelable;
junyulai06835112019-01-03 18:50:15 +080028import android.system.OsConstants;
29
30import java.net.Inet4Address;
31import java.net.InetAddress;
32import java.nio.ByteBuffer;
33import java.nio.ByteOrder;
Chiachang Wangd4d035d2020-03-13 16:37:04 +080034import java.util.Objects;
junyulai06835112019-01-03 18:50:15 +080035
36/** @hide */
Aaron Huang8e5e8c92020-01-09 22:04:21 +080037@SystemApi
Aaron Huang76985bd2019-04-23 22:17:16 +080038public final class NattKeepalivePacketData extends KeepalivePacketData implements Parcelable {
Aaron Huang08d9ade2019-10-02 01:39:46 +080039 private static final int IPV4_HEADER_LENGTH = 20;
40 private static final int UDP_HEADER_LENGTH = 8;
41
junyulai06835112019-01-03 18:50:15 +080042 // This should only be constructed via static factory methods, such as
43 // nattKeepalivePacket
Aaron Huang8e5e8c92020-01-09 22:04:21 +080044 public NattKeepalivePacketData(@NonNull InetAddress srcAddress, int srcPort,
45 @NonNull InetAddress dstAddress, int dstPort, @NonNull byte[] data) throws
junyulai06835112019-01-03 18:50:15 +080046 InvalidPacketException {
47 super(srcAddress, srcPort, dstAddress, dstPort, data);
48 }
49
50 /**
51 * Factory method to create Nat-T keepalive packet structure.
Aaron Huang8e5e8c92020-01-09 22:04:21 +080052 * @hide
junyulai06835112019-01-03 18:50:15 +080053 */
54 public static NattKeepalivePacketData nattKeepalivePacket(
55 InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort)
56 throws InvalidPacketException {
57
58 if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) {
markchien150e1912018-12-27 22:49:51 +080059 throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
junyulai06835112019-01-03 18:50:15 +080060 }
61
62 if (dstPort != NattSocketKeepalive.NATT_PORT) {
markchien150e1912018-12-27 22:49:51 +080063 throw new InvalidPacketException(ERROR_INVALID_PORT);
junyulai06835112019-01-03 18:50:15 +080064 }
65
66 int length = IPV4_HEADER_LENGTH + UDP_HEADER_LENGTH + 1;
67 ByteBuffer buf = ByteBuffer.allocate(length);
68 buf.order(ByteOrder.BIG_ENDIAN);
69 buf.putShort((short) 0x4500); // IP version and TOS
70 buf.putShort((short) length);
71 buf.putInt(0); // ID, flags, offset
72 buf.put((byte) 64); // TTL
73 buf.put((byte) OsConstants.IPPROTO_UDP);
74 int ipChecksumOffset = buf.position();
75 buf.putShort((short) 0); // IP checksum
76 buf.put(srcAddress.getAddress());
77 buf.put(dstAddress.getAddress());
78 buf.putShort((short) srcPort);
79 buf.putShort((short) dstPort);
80 buf.putShort((short) (length - 20)); // UDP length
81 int udpChecksumOffset = buf.position();
82 buf.putShort((short) 0); // UDP checksum
83 buf.put((byte) 0xff); // NAT-T keepalive
84 buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0));
85 buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_LENGTH));
86
87 return new NattKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array());
88 }
Aaron Huang76985bd2019-04-23 22:17:16 +080089
junyulai02abbfd2019-06-03 17:51:41 +080090 /** Parcelable Implementation */
91 public int describeContents() {
92 return 0;
Aaron Huang76985bd2019-04-23 22:17:16 +080093 }
junyulai02abbfd2019-06-03 17:51:41 +080094
95 /** Write to parcel */
Aaron Huang8e5e8c92020-01-09 22:04:21 +080096 public void writeToParcel(@NonNull Parcel out, int flags) {
Aaron Huang87453842020-03-18 19:24:31 +080097 out.writeString(getSrcAddress().getHostAddress());
98 out.writeString(getDstAddress().getHostAddress());
99 out.writeInt(getSrcPort());
100 out.writeInt(getDstPort());
junyulai02abbfd2019-06-03 17:51:41 +0800101 }
102
103 /** Parcelable Creator */
Aaron Huang8e5e8c92020-01-09 22:04:21 +0800104 public static final @NonNull Parcelable.Creator<NattKeepalivePacketData> CREATOR =
junyulai02abbfd2019-06-03 17:51:41 +0800105 new Parcelable.Creator<NattKeepalivePacketData>() {
106 public NattKeepalivePacketData createFromParcel(Parcel in) {
107 final InetAddress srcAddress =
108 InetAddresses.parseNumericAddress(in.readString());
109 final InetAddress dstAddress =
110 InetAddresses.parseNumericAddress(in.readString());
111 final int srcPort = in.readInt();
112 final int dstPort = in.readInt();
113 try {
114 return NattKeepalivePacketData.nattKeepalivePacket(srcAddress, srcPort,
115 dstAddress, dstPort);
116 } catch (InvalidPacketException e) {
117 throw new IllegalArgumentException(
Aaron Huang87453842020-03-18 19:24:31 +0800118 "Invalid NAT-T keepalive data: " + e.getError());
junyulai02abbfd2019-06-03 17:51:41 +0800119 }
120 }
121
122 public NattKeepalivePacketData[] newArray(int size) {
123 return new NattKeepalivePacketData[size];
124 }
125 };
Chiachang Wangd4d035d2020-03-13 16:37:04 +0800126
127 @Override
128 public boolean equals(@Nullable final Object o) {
129 if (!(o instanceof NattKeepalivePacketData)) return false;
130 final NattKeepalivePacketData other = (NattKeepalivePacketData) o;
Aaron Huang87453842020-03-18 19:24:31 +0800131 final InetAddress srcAddress = getSrcAddress();
132 final InetAddress dstAddress = getDstAddress();
133 return srcAddress.equals(other.getSrcAddress())
134 && dstAddress.equals(other.getDstAddress())
135 && getSrcPort() == other.getSrcPort()
136 && getDstPort() == other.getDstPort();
Chiachang Wangd4d035d2020-03-13 16:37:04 +0800137 }
138
139 @Override
140 public int hashCode() {
Aaron Huang87453842020-03-18 19:24:31 +0800141 return Objects.hash(getSrcAddress(), getDstAddress(), getSrcPort(), getDstPort());
Chiachang Wangd4d035d2020-03-13 16:37:04 +0800142 }
junyulai06835112019-01-03 18:50:15 +0800143}