blob: c4f8fc281f25dc775cf9d3443f3054479e78164c [file] [log] [blame]
junyulai1fb0c952019-01-03 18:50:15 +08001/*
junyulai97e37752019-06-04 05:26:38 -07002 * Copyright (C) 2019 The Android Open Source Project
junyulai1fb0c952019-01-03 18:50:15 +08003 *
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 Huangaead9c62020-01-09 22:04:21 +080019import static android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS;
20import static android.net.InvalidPacketException.ERROR_INVALID_PORT;
markchiene5591ce2018-12-27 22:49:51 +080021
Aaron Huangaead9c62020-01-09 22:04:21 +080022import android.annotation.NonNull;
Chiachang Wang5b710612020-03-13 16:37:04 +080023import android.annotation.Nullable;
Aaron Huangaead9c62020-01-09 22:04:21 +080024import android.annotation.SystemApi;
junyulai97e37752019-06-04 05:26:38 -070025import android.os.Parcel;
Aaron Huang311bac92019-04-23 22:17:16 +080026import android.os.Parcelable;
junyulai1fb0c952019-01-03 18:50:15 +080027import android.system.OsConstants;
28
Remi NGUYEN VAN7f3a7512020-09-24 18:31:55 +090029import com.android.net.module.util.IpUtils;
30
junyulai1fb0c952019-01-03 18:50:15 +080031import java.net.Inet4Address;
32import java.net.InetAddress;
33import java.nio.ByteBuffer;
34import java.nio.ByteOrder;
Chiachang Wang5b710612020-03-13 16:37:04 +080035import java.util.Objects;
junyulai1fb0c952019-01-03 18:50:15 +080036
37/** @hide */
Aaron Huangaead9c62020-01-09 22:04:21 +080038@SystemApi
Aaron Huang311bac92019-04-23 22:17:16 +080039public final class NattKeepalivePacketData extends KeepalivePacketData implements Parcelable {
Aaron Huang441e4992019-10-02 01:39:46 +080040 private static final int IPV4_HEADER_LENGTH = 20;
41 private static final int UDP_HEADER_LENGTH = 8;
42
junyulai1fb0c952019-01-03 18:50:15 +080043 // This should only be constructed via static factory methods, such as
44 // nattKeepalivePacket
Aaron Huangaead9c62020-01-09 22:04:21 +080045 public NattKeepalivePacketData(@NonNull InetAddress srcAddress, int srcPort,
46 @NonNull InetAddress dstAddress, int dstPort, @NonNull byte[] data) throws
junyulai1fb0c952019-01-03 18:50:15 +080047 InvalidPacketException {
48 super(srcAddress, srcPort, dstAddress, dstPort, data);
49 }
50
51 /**
52 * Factory method to create Nat-T keepalive packet structure.
Aaron Huangaead9c62020-01-09 22:04:21 +080053 * @hide
junyulai1fb0c952019-01-03 18:50:15 +080054 */
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)) {
markchiene5591ce2018-12-27 22:49:51 +080060 throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
junyulai1fb0c952019-01-03 18:50:15 +080061 }
62
63 if (dstPort != NattSocketKeepalive.NATT_PORT) {
markchiene5591ce2018-12-27 22:49:51 +080064 throw new InvalidPacketException(ERROR_INVALID_PORT);
junyulai1fb0c952019-01-03 18:50:15 +080065 }
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 }
Aaron Huang311bac92019-04-23 22:17:16 +080090
junyulai97e37752019-06-04 05:26:38 -070091 /** Parcelable Implementation */
92 public int describeContents() {
93 return 0;
Aaron Huang311bac92019-04-23 22:17:16 +080094 }
junyulai97e37752019-06-04 05:26:38 -070095
96 /** Write to parcel */
Aaron Huangaead9c62020-01-09 22:04:21 +080097 public void writeToParcel(@NonNull Parcel out, int flags) {
Aaron Huang005f9d12020-03-18 19:24:31 +080098 out.writeString(getSrcAddress().getHostAddress());
99 out.writeString(getDstAddress().getHostAddress());
100 out.writeInt(getSrcPort());
101 out.writeInt(getDstPort());
junyulai97e37752019-06-04 05:26:38 -0700102 }
103
104 /** Parcelable Creator */
Aaron Huangaead9c62020-01-09 22:04:21 +0800105 public static final @NonNull Parcelable.Creator<NattKeepalivePacketData> CREATOR =
junyulai97e37752019-06-04 05:26:38 -0700106 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(
Aaron Huang005f9d12020-03-18 19:24:31 +0800119 "Invalid NAT-T keepalive data: " + e.getError());
junyulai97e37752019-06-04 05:26:38 -0700120 }
121 }
122
123 public NattKeepalivePacketData[] newArray(int size) {
124 return new NattKeepalivePacketData[size];
125 }
126 };
Chiachang Wang5b710612020-03-13 16:37:04 +0800127
128 @Override
129 public boolean equals(@Nullable final Object o) {
130 if (!(o instanceof NattKeepalivePacketData)) return false;
131 final NattKeepalivePacketData other = (NattKeepalivePacketData) o;
Aaron Huang005f9d12020-03-18 19:24:31 +0800132 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();
Chiachang Wang5b710612020-03-13 16:37:04 +0800138 }
139
140 @Override
141 public int hashCode() {
Aaron Huang005f9d12020-03-18 19:24:31 +0800142 return Objects.hash(getSrcAddress(), getDstAddress(), getSrcPort(), getDstPort());
Chiachang Wang5b710612020-03-13 16:37:04 +0800143 }
junyulai1fb0c952019-01-03 18:50:15 +0800144}