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