• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package android.net;
18 
19 import static android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS;
20 import static android.net.InvalidPacketException.ERROR_INVALID_PORT;
21 
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.SystemApi;
25 import android.net.util.IpUtils;
26 import android.os.Parcel;
27 import android.os.Parcelable;
28 import android.system.OsConstants;
29 
30 import java.net.Inet4Address;
31 import java.net.InetAddress;
32 import java.nio.ByteBuffer;
33 import java.nio.ByteOrder;
34 import java.util.Objects;
35 
36 /** @hide */
37 @SystemApi
38 public final class NattKeepalivePacketData extends KeepalivePacketData implements Parcelable {
39     private static final int IPV4_HEADER_LENGTH = 20;
40     private static final int UDP_HEADER_LENGTH = 8;
41 
42     // This should only be constructed via static factory methods, such as
43     // nattKeepalivePacket
NattKeepalivePacketData(@onNull InetAddress srcAddress, int srcPort, @NonNull InetAddress dstAddress, int dstPort, @NonNull byte[] data)44     public NattKeepalivePacketData(@NonNull InetAddress srcAddress, int srcPort,
45             @NonNull InetAddress dstAddress, int dstPort, @NonNull byte[] data) throws
46             InvalidPacketException {
47         super(srcAddress, srcPort, dstAddress, dstPort, data);
48     }
49 
50     /**
51      * Factory method to create Nat-T keepalive packet structure.
52      * @hide
53      */
nattKeepalivePacket( InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort)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)) {
59             throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
60         }
61 
62         if (dstPort != NattSocketKeepalive.NATT_PORT) {
63             throw new InvalidPacketException(ERROR_INVALID_PORT);
64         }
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     }
89 
90     /** Parcelable Implementation */
describeContents()91     public int describeContents() {
92         return 0;
93     }
94 
95     /** Write to parcel */
writeToParcel(@onNull Parcel out, int flags)96     public void writeToParcel(@NonNull Parcel out, int flags) {
97         out.writeString(getSrcAddress().getHostAddress());
98         out.writeString(getDstAddress().getHostAddress());
99         out.writeInt(getSrcPort());
100         out.writeInt(getDstPort());
101     }
102 
103     /** Parcelable Creator */
104     public static final @NonNull Parcelable.Creator<NattKeepalivePacketData> CREATOR =
105             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(
118                                 "Invalid NAT-T keepalive data: " + e.getError());
119                     }
120                 }
121 
122                 public NattKeepalivePacketData[] newArray(int size) {
123                     return new NattKeepalivePacketData[size];
124                 }
125             };
126 
127     @Override
equals(@ullable final Object o)128     public boolean equals(@Nullable final Object o) {
129         if (!(o instanceof NattKeepalivePacketData)) return false;
130         final NattKeepalivePacketData other = (NattKeepalivePacketData) o;
131         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();
137     }
138 
139     @Override
hashCode()140     public int hashCode() {
141         return Objects.hash(getSrcAddress(), getDstAddress(), getSrcPort(), getDstPort());
142     }
143 }
144