blob: c4f8fc281f25dc775cf9d3443f3054479e78164c [file] [log] [blame]
Remi NGUYEN VANfbbccbc2021-01-15 18:08:24 +09001/*
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
19import static android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS;
20import static android.net.InvalidPacketException.ERROR_INVALID_PORT;
21
22import android.annotation.NonNull;
23import android.annotation.Nullable;
24import android.annotation.SystemApi;
25import android.os.Parcel;
26import android.os.Parcelable;
27import android.system.OsConstants;
28
29import com.android.net.module.util.IpUtils;
30
31import java.net.Inet4Address;
32import java.net.InetAddress;
33import java.nio.ByteBuffer;
34import java.nio.ByteOrder;
35import java.util.Objects;
36
37/** @hide */
38@SystemApi
39public final class NattKeepalivePacketData extends KeepalivePacketData implements Parcelable {
40 private static final int IPV4_HEADER_LENGTH = 20;
41 private static final int UDP_HEADER_LENGTH = 8;
42
43 // This should only be constructed via static factory methods, such as
44 // nattKeepalivePacket
45 public NattKeepalivePacketData(@NonNull InetAddress srcAddress, int srcPort,
46 @NonNull InetAddress dstAddress, int dstPort, @NonNull byte[] data) throws
47 InvalidPacketException {
48 super(srcAddress, srcPort, dstAddress, dstPort, data);
49 }
50
51 /**
52 * Factory method to create Nat-T keepalive packet structure.
53 * @hide
54 */
55 public static NattKeepalivePacketData nattKeepalivePacket(
56 InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort)
57 throws InvalidPacketException {
58
59 if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) {
60 throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
61 }
62
63 if (dstPort != NattSocketKeepalive.NATT_PORT) {
64 throw new InvalidPacketException(ERROR_INVALID_PORT);
65 }
66
67 int length = IPV4_HEADER_LENGTH + UDP_HEADER_LENGTH + 1;
68 ByteBuffer buf = ByteBuffer.allocate(length);
69 buf.order(ByteOrder.BIG_ENDIAN);
70 buf.putShort((short) 0x4500); // IP version and TOS
71 buf.putShort((short) length);
72 buf.putInt(0); // ID, flags, offset
73 buf.put((byte) 64); // TTL
74 buf.put((byte) OsConstants.IPPROTO_UDP);
75 int ipChecksumOffset = buf.position();
76 buf.putShort((short) 0); // IP checksum
77 buf.put(srcAddress.getAddress());
78 buf.put(dstAddress.getAddress());
79 buf.putShort((short) srcPort);
80 buf.putShort((short) dstPort);
81 buf.putShort((short) (length - 20)); // UDP length
82 int udpChecksumOffset = buf.position();
83 buf.putShort((short) 0); // UDP checksum
84 buf.put((byte) 0xff); // NAT-T keepalive
85 buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0));
86 buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_LENGTH));
87
88 return new NattKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array());
89 }
90
91 /** Parcelable Implementation */
92 public int describeContents() {
93 return 0;
94 }
95
96 /** Write to parcel */
97 public void writeToParcel(@NonNull Parcel out, int flags) {
98 out.writeString(getSrcAddress().getHostAddress());
99 out.writeString(getDstAddress().getHostAddress());
100 out.writeInt(getSrcPort());
101 out.writeInt(getDstPort());
102 }
103
104 /** Parcelable Creator */
105 public static final @NonNull Parcelable.Creator<NattKeepalivePacketData> CREATOR =
106 new Parcelable.Creator<NattKeepalivePacketData>() {
107 public NattKeepalivePacketData createFromParcel(Parcel in) {
108 final InetAddress srcAddress =
109 InetAddresses.parseNumericAddress(in.readString());
110 final InetAddress dstAddress =
111 InetAddresses.parseNumericAddress(in.readString());
112 final int srcPort = in.readInt();
113 final int dstPort = in.readInt();
114 try {
115 return NattKeepalivePacketData.nattKeepalivePacket(srcAddress, srcPort,
116 dstAddress, dstPort);
117 } catch (InvalidPacketException e) {
118 throw new IllegalArgumentException(
119 "Invalid NAT-T keepalive data: " + e.getError());
120 }
121 }
122
123 public NattKeepalivePacketData[] newArray(int size) {
124 return new NattKeepalivePacketData[size];
125 }
126 };
127
128 @Override
129 public boolean equals(@Nullable final Object o) {
130 if (!(o instanceof NattKeepalivePacketData)) return false;
131 final NattKeepalivePacketData other = (NattKeepalivePacketData) o;
132 final InetAddress srcAddress = getSrcAddress();
133 final InetAddress dstAddress = getDstAddress();
134 return srcAddress.equals(other.getSrcAddress())
135 && dstAddress.equals(other.getDstAddress())
136 && getSrcPort() == other.getSrcPort()
137 && getDstPort() == other.getDstPort();
138 }
139
140 @Override
141 public int hashCode() {
142 return Objects.hash(getSrcAddress(), getDstAddress(), getSrcPort(), getDstPort());
143 }
144}