1 /*
2  * Copyright (C) 2015 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 com.android.server.connectivity;
18 
19 import android.system.OsConstants;
20 import android.net.ConnectivityManager;
21 import android.net.NetworkUtils;
22 import android.net.util.IpUtils;
23 
24 import java.net.Inet4Address;
25 import java.net.Inet6Address;
26 import java.net.InetAddress;
27 import java.nio.ByteBuffer;
28 import java.nio.ByteOrder;
29 
30 import static android.net.ConnectivityManager.PacketKeepalive.*;
31 
32 /**
33  * Represents the actual packets that are sent by the
34  * {@link android.net.ConnectivityManager.PacketKeepalive} API.
35  *
36  * @hide
37  */
38 public class KeepalivePacketData {
39     /** Protocol of the packet to send; one of the OsConstants.ETH_P_* values. */
40     public final int protocol;
41 
42     /** Source IP address */
43     public final InetAddress srcAddress;
44 
45     /** Destination IP address */
46     public final InetAddress dstAddress;
47 
48     /** Source port */
49     public final int srcPort;
50 
51     /** Destination port */
52     public final int dstPort;
53 
54     /** Destination MAC address. Can change if routing changes. */
55     public byte[] dstMac;
56 
57     /** Packet data. A raw byte string of packet data, not including the link-layer header. */
58     public final byte[] data;
59 
60     private static final int IPV4_HEADER_LENGTH = 20;
61     private static final int UDP_HEADER_LENGTH = 8;
62 
KeepalivePacketData(InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort, byte[] data)63     protected KeepalivePacketData(InetAddress srcAddress, int srcPort,
64             InetAddress dstAddress, int dstPort, byte[] data) throws InvalidPacketException {
65         this.srcAddress = srcAddress;
66         this.dstAddress = dstAddress;
67         this.srcPort = srcPort;
68         this.dstPort = dstPort;
69         this.data = data;
70 
71         // Check we have two IP addresses of the same family.
72         if (srcAddress == null || dstAddress == null ||
73                 !srcAddress.getClass().getName().equals(dstAddress.getClass().getName())) {
74             throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
75         }
76 
77         // Set the protocol.
78         if (this.dstAddress instanceof Inet4Address) {
79             this.protocol = OsConstants.ETH_P_IP;
80         } else if (this.dstAddress instanceof Inet6Address) {
81             this.protocol = OsConstants.ETH_P_IPV6;
82         } else {
83             throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
84         }
85 
86         // Check the ports.
87         if (!IpUtils.isValidUdpOrTcpPort(srcPort) || !IpUtils.isValidUdpOrTcpPort(dstPort)) {
88             throw new InvalidPacketException(ERROR_INVALID_PORT);
89         }
90     }
91 
92     public static class InvalidPacketException extends Exception {
93         final public int error;
InvalidPacketException(int error)94         public InvalidPacketException(int error) {
95             this.error = error;
96         }
97     }
98 
99     /**
100      * Creates an IPsec NAT-T keepalive packet with the specified parameters.
101      */
nattKeepalivePacket( InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort)102     public static KeepalivePacketData nattKeepalivePacket(
103             InetAddress srcAddress, int srcPort,
104             InetAddress dstAddress, int dstPort) throws InvalidPacketException {
105 
106         if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) {
107             throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
108         }
109 
110         if (dstPort != NATT_PORT) {
111             throw new InvalidPacketException(ERROR_INVALID_PORT);
112         }
113 
114         int length = IPV4_HEADER_LENGTH + UDP_HEADER_LENGTH + 1;
115         ByteBuffer buf = ByteBuffer.allocate(length);
116         buf.order(ByteOrder.BIG_ENDIAN);
117         buf.putShort((short) 0x4500);             // IP version and TOS
118         buf.putShort((short) length);
119         buf.putInt(0);                            // ID, flags, offset
120         buf.put((byte) 64);                       // TTL
121         buf.put((byte) OsConstants.IPPROTO_UDP);
122         int ipChecksumOffset = buf.position();
123         buf.putShort((short) 0);                  // IP checksum
124         buf.put(srcAddress.getAddress());
125         buf.put(dstAddress.getAddress());
126         buf.putShort((short) srcPort);
127         buf.putShort((short) dstPort);
128         buf.putShort((short) (length - 20));      // UDP length
129         int udpChecksumOffset = buf.position();
130         buf.putShort((short) 0);                  // UDP checksum
131         buf.put((byte) 0xff);                     // NAT-T keepalive
132         buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0));
133         buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_LENGTH));
134 
135         return new KeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array());
136     }
137 }
138