• 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.ipsec.ike;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.net.InetAddresses;
22 import android.net.ipsec.ike.exceptions.InvalidSyntaxException;
23 import android.os.PersistableBundle;
24 import android.util.ArraySet;
25 
26 import com.android.internal.annotations.VisibleForTesting;
27 
28 import java.lang.annotation.Retention;
29 import java.lang.annotation.RetentionPolicy;
30 import java.net.Inet4Address;
31 import java.net.Inet6Address;
32 import java.net.InetAddress;
33 import java.net.UnknownHostException;
34 import java.nio.BufferOverflowException;
35 import java.nio.ByteBuffer;
36 import java.util.Objects;
37 
38 /**
39  * IkeTrafficSelector represents a Traffic Selector of a Child Session.
40  *
41  * <p>Traffic Selectors specify addresses that are acceptable within the IPsec SA.
42  *
43  * <p>Callers can propose {@link IkeTrafficSelector}s when building a {@link ChildSessionParams} and
44  * receive the negotiated {@link IkeTrafficSelector}s via a {@link ChildSessionConfiguration}.
45  *
46  * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.13">RFC 7296, Internet Key Exchange
47  *     Protocol Version 2 (IKEv2)</a>
48  */
49 public final class IkeTrafficSelector {
50 
51     // IpProtocolId consists of standard IP Protocol IDs.
52     /** @hide */
53     @Retention(RetentionPolicy.SOURCE)
54     @IntDef({IP_PROTOCOL_ID_UNSPEC, IP_PROTOCOL_ID_ICMP, IP_PROTOCOL_ID_TCP, IP_PROTOCOL_ID_UDP})
55     public @interface IpProtocolId {}
56 
57     // Zero value is re-defined by IKE to indicate that all IP protocols are acceptable.
58     /** @hide */
59     @VisibleForTesting static final int IP_PROTOCOL_ID_UNSPEC = 0;
60     /** @hide */
61     @VisibleForTesting static final int IP_PROTOCOL_ID_ICMP = 1;
62     /** @hide */
63     @VisibleForTesting static final int IP_PROTOCOL_ID_TCP = 6;
64     /** @hide */
65     @VisibleForTesting static final int IP_PROTOCOL_ID_UDP = 17;
66 
67     private static final ArraySet<Integer> IP_PROTOCOL_ID_SET = new ArraySet<>();
68 
69     static {
70         IP_PROTOCOL_ID_SET.add(IP_PROTOCOL_ID_UNSPEC);
71         IP_PROTOCOL_ID_SET.add(IP_PROTOCOL_ID_ICMP);
72         IP_PROTOCOL_ID_SET.add(IP_PROTOCOL_ID_TCP);
73         IP_PROTOCOL_ID_SET.add(IP_PROTOCOL_ID_UDP);
74     }
75 
76     /**
77      * TrafficSelectorType consists of IKE standard Traffic Selector Types.
78      *
79      * @see <a
80      *     href="https://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml">Internet
81      *     Key Exchange Version 2 (IKEv2) Parameters</a>
82      * @hide
83      */
84     @Retention(RetentionPolicy.SOURCE)
85     @IntDef({TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE, TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE})
86     public @interface TrafficSelectorType {}
87 
88     /** @hide */
89     public static final int TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE = 7;
90     /** @hide */
91     public static final int TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE = 8;
92 
93     /** @hide */
94     public static final int PORT_NUMBER_MIN = 0;
95     /** @hide */
96     public static final int PORT_NUMBER_MAX = 65535;
97 
98     // TODO: Consider defining these constants in a central place in Connectivity.
99     private static final int IPV4_ADDR_LEN = 4;
100     private static final int IPV6_ADDR_LEN = 16;
101 
102     @VisibleForTesting static final int TRAFFIC_SELECTOR_IPV4_LEN = 16;
103     @VisibleForTesting static final int TRAFFIC_SELECTOR_IPV6_LEN = 40;
104 
105     private static final String START_PORT_KEY = "startPort";
106     private static final String END_PORT_KEY = "endPort";
107     private static final String START_ADDRESS_KEY = "startingAddress";
108     private static final String END_ADDRESS_KEY = "endingAddress";
109 
110     /** @hide */
111     public final int tsType;
112     /** @hide */
113     public final int ipProtocolId;
114     /** @hide */
115     public final int selectorLength;
116     /** The smallest port number allowed by this Traffic Selector. Informational only. */
117     public final int startPort;
118     /** The largest port number allowed by this Traffic Selector. Informational only. */
119     public final int endPort;
120     /** The smallest address included in this Traffic Selector. */
121     @NonNull public final InetAddress startingAddress;
122     /** The largest address included in this Traffic Selector. */
123     @NonNull public final InetAddress endingAddress;
124 
IkeTrafficSelector( int tsType, int ipProtocolId, int selectorLength, int startPort, int endPort, InetAddress startingAddress, InetAddress endingAddress)125     private IkeTrafficSelector(
126             int tsType,
127             int ipProtocolId,
128             int selectorLength,
129             int startPort,
130             int endPort,
131             InetAddress startingAddress,
132             InetAddress endingAddress) {
133         this.tsType = tsType;
134         this.ipProtocolId = ipProtocolId;
135         this.selectorLength = selectorLength;
136 
137         // Ports & Addresses previously validated in decodeIkeTrafficSelectors()
138         this.startPort = startPort;
139         this.endPort = endPort;
140         this.startingAddress = startingAddress;
141         this.endingAddress = endingAddress;
142     }
143 
144     /**
145      * Construct an instance of {@link IkeTrafficSelector} for negotiating a Child Session.
146      *
147      * <p>Android platform does not support port-based routing. The port range negotiation is only
148      * informational.
149      *
150      * @param startPort the smallest port number allowed by this Traffic Selector.
151      * @param endPort the largest port number allowed by this Traffic Selector.
152      * @param startingAddress the smallest address included in this Traffic Selector.
153      * @param endingAddress the largest address included in this Traffic Selector.
154      */
IkeTrafficSelector( int startPort, int endPort, @NonNull InetAddress startingAddress, @NonNull InetAddress endingAddress)155     public IkeTrafficSelector(
156             int startPort,
157             int endPort,
158             @NonNull InetAddress startingAddress,
159             @NonNull InetAddress endingAddress) {
160         this(getTsType(startingAddress), startPort, endPort, startingAddress, endingAddress);
161     }
162 
getTsType(InetAddress address)163     private static int getTsType(InetAddress address) {
164         if (address instanceof Inet4Address) {
165             return TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE;
166         }
167         return TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE;
168     }
169 
170     /**
171      * Construct an instance of IkeTrafficSelector for building an outbound IKE message.
172      *
173      * @param tsType the Traffic Selector type.
174      * @param startPort the smallest port number allowed by this Traffic Selector.
175      * @param endPort the largest port number allowed by this Traffic Selector.
176      * @param startingAddress the smallest address included in this Traffic Selector.
177      * @param endingAddress the largest address included in this Traffic Selector.
178      * @hide
179      */
IkeTrafficSelector( @rafficSelectorType int tsType, int startPort, int endPort, InetAddress startingAddress, InetAddress endingAddress)180     public IkeTrafficSelector(
181             @TrafficSelectorType int tsType,
182             int startPort,
183             int endPort,
184             InetAddress startingAddress,
185             InetAddress endingAddress) {
186 
187         this.tsType = tsType;
188         this.ipProtocolId = IP_PROTOCOL_ID_UNSPEC;
189 
190         switch (tsType) {
191             case TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE:
192                 this.selectorLength = TRAFFIC_SELECTOR_IPV4_LEN;
193 
194                 if (!(startingAddress instanceof Inet4Address)
195                         || !(endingAddress instanceof Inet4Address)) {
196                     throw new IllegalArgumentException(
197                             "Invalid address range: TS_IPV4_ADDR_RANGE requires IPv4 addresses.");
198                 }
199 
200                 break;
201             case TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE:
202                 this.selectorLength = TRAFFIC_SELECTOR_IPV6_LEN;
203 
204                 if (!(startingAddress instanceof Inet6Address)
205                         || !(endingAddress instanceof Inet6Address)) {
206                     throw new IllegalArgumentException(
207                             "Invalid address range: TS_IPV6_ADDR_RANGE requires IPv6 addresses.");
208                 }
209                 break;
210             default:
211                 throw new IllegalArgumentException("Unrecognized Traffic Selector type.");
212         }
213 
214         if (compareInetAddressTo(startingAddress, endingAddress) > 0) {
215             throw new IllegalArgumentException("Received invalid address range.");
216         }
217 
218         if (!isPortRangeValid(startPort, endPort)) {
219             throw new IllegalArgumentException(
220                     "Invalid port range. startPort: " + startPort + " endPort: " + endPort);
221         }
222 
223         this.startPort = startPort;
224         this.endPort = endPort;
225         this.startingAddress = startingAddress;
226         this.endingAddress = endingAddress;
227     }
228 
229     /**
230      * Constructs this object by deserializing a PersistableBundle
231      *
232      * @hide
233      */
234     @NonNull
fromPersistableBundle(@onNull PersistableBundle in)235     public static IkeTrafficSelector fromPersistableBundle(@NonNull PersistableBundle in) {
236         Objects.requireNonNull(in, "PersistableBundle not provided");
237 
238         int startPort = in.getInt(START_PORT_KEY);
239         int endPort = in.getInt(END_PORT_KEY);
240 
241         InetAddress startingAddress =
242                 InetAddresses.parseNumericAddress(in.getString(START_ADDRESS_KEY));
243         Objects.requireNonNull(in, "startAddress not provided");
244         InetAddress endingAddress =
245                 InetAddresses.parseNumericAddress(in.getString(END_ADDRESS_KEY));
246         Objects.requireNonNull(in, "endAddress not provided");
247 
248         return new IkeTrafficSelector(startPort, endPort, startingAddress, endingAddress);
249     }
250 
251     /**
252      * Serializes this object to a PersistableBundle
253      *
254      * @hide
255      */
256     @NonNull
toPersistableBundle()257     public PersistableBundle toPersistableBundle() {
258         final PersistableBundle result = new PersistableBundle();
259 
260         result.putInt(START_PORT_KEY, startPort);
261         result.putInt(END_PORT_KEY, endPort);
262         result.putString(START_ADDRESS_KEY, startingAddress.getHostAddress());
263         result.putString(END_ADDRESS_KEY, endingAddress.getHostAddress());
264 
265         return result;
266     }
267 
268     /**
269      * Decode IkeTrafficSelectors from inbound Traffic Selector Payload.
270      *
271      * <p>This method is only called by IkeTsPayload when decoding inbound IKE message.
272      *
273      * @param numTs number or Traffic Selectors
274      * @param tsBytes encoded byte array of Traffic Selectors
275      * @return an array of decoded IkeTrafficSelectors
276      * @throws InvalidSyntaxException if received bytes are malformed.
277      * @hide
278      */
decodeIkeTrafficSelectors(int numTs, byte[] tsBytes)279     public static IkeTrafficSelector[] decodeIkeTrafficSelectors(int numTs, byte[] tsBytes)
280             throws InvalidSyntaxException {
281         IkeTrafficSelector[] tsArray = new IkeTrafficSelector[numTs];
282         ByteBuffer inputBuffer = ByteBuffer.wrap(tsBytes);
283 
284         try {
285             for (int i = 0; i < numTs; i++) {
286                 int tsType = Byte.toUnsignedInt(inputBuffer.get());
287                 switch (tsType) {
288                     case TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE:
289                         tsArray[i] = decodeTrafficSelector(inputBuffer,
290                                 TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE);
291                         break;
292                     case TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE:
293                         tsArray[i] = decodeTrafficSelector(inputBuffer,
294                                 TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE);
295                         break;
296                     default:
297                         throw new InvalidSyntaxException(
298                                 "Invalid Traffic Selector type: " + tsType);
299                 }
300             }
301         } catch (BufferOverflowException e) {
302             // Throw exception if any Traffic Selector has invalid length.
303             throw new InvalidSyntaxException(e);
304         }
305 
306         if (inputBuffer.remaining() != 0) {
307             throw new InvalidSyntaxException(
308                     "Unexpected trailing characters of Traffic Selectors.");
309         }
310 
311         return tsArray;
312     }
313 
314     // Decode Traffic Selector from a ByteBuffer. A BufferOverflowException will be thrown and
315     // caught by method caller if operation reaches the input ByteBuffer's limit.
decodeTrafficSelector(ByteBuffer inputBuffer, int tsType)316     private static IkeTrafficSelector decodeTrafficSelector(ByteBuffer inputBuffer, int tsType)
317             throws InvalidSyntaxException {
318         // Decode and validate IP Protocol ID
319         int ipProtocolId = Byte.toUnsignedInt(inputBuffer.get());
320         if (!IP_PROTOCOL_ID_SET.contains(ipProtocolId)) {
321             throw new InvalidSyntaxException("Invalid IP Protocol ID.");
322         }
323 
324         // Decode and validate Selector Length
325         boolean isTsIpv4 = tsType == TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE;
326         int expectedTsLen = isTsIpv4 ? TRAFFIC_SELECTOR_IPV4_LEN : TRAFFIC_SELECTOR_IPV6_LEN;
327         int tsLength = Short.toUnsignedInt(inputBuffer.getShort());
328         if (expectedTsLen != tsLength) {
329             throw new InvalidSyntaxException("Invalid Traffic Selector Length.");
330         }
331 
332         // Decode and validate ports
333         int startPort = Short.toUnsignedInt(inputBuffer.getShort());
334         int endPort = Short.toUnsignedInt(inputBuffer.getShort());
335         if (!isPortRangeValid(startPort, endPort)) {
336             throw new InvalidSyntaxException(
337                     "Received invalid port range. startPort: "
338                             + startPort
339                             + " endPort: "
340                             + endPort);
341         }
342 
343         // Decode and validate IP addresses
344         int expectedAddrLen = isTsIpv4 ? IPV4_ADDR_LEN : IPV6_ADDR_LEN;
345         byte[] startAddressBytes = new byte[expectedAddrLen];
346         byte[] endAddressBytes = new byte[expectedAddrLen];
347         inputBuffer.get(startAddressBytes);
348         inputBuffer.get(endAddressBytes);
349         try {
350             InetAddress startAddress = InetAddress.getByAddress(startAddressBytes);
351             InetAddress endAddress = InetAddress.getByAddress(endAddressBytes);
352 
353             boolean isStartAddrIpv4 = startAddress instanceof Inet4Address;
354             boolean isEndAddrIpv4 = endAddress instanceof Inet4Address;
355             if (isTsIpv4 != isStartAddrIpv4 || isTsIpv4 != isEndAddrIpv4) {
356                 throw new InvalidSyntaxException("Invalid IP address family");
357             }
358 
359             // Validate address range.
360             if (compareInetAddressTo(startAddress, endAddress) > 0) {
361                 throw new InvalidSyntaxException("Received invalid IP address range.");
362             }
363 
364             return new IkeTrafficSelector(
365                     tsType,
366                     ipProtocolId,
367                     expectedTsLen,
368                     startPort,
369                     endPort,
370                     startAddress,
371                     endAddress);
372         } catch (ClassCastException | UnknownHostException | IllegalArgumentException e) {
373             throw new InvalidSyntaxException(e);
374         }
375     }
376 
377     // Validate port range.
isPortRangeValid(int startPort, int endPort)378     private static boolean isPortRangeValid(int startPort, int endPort) {
379         return (startPort >= PORT_NUMBER_MIN
380                 && startPort <= PORT_NUMBER_MAX
381                 && endPort >= PORT_NUMBER_MIN
382                 && endPort <= PORT_NUMBER_MAX
383                 && startPort <= endPort);
384     }
385 
386     // Compare two InetAddresses. Return -1 if the first input is smaller; 1 if the second input is
387     // smaller; 0 if two addresses are equal.
388     // TODO: Consider moving it to the platform code in the future./
compareInetAddressTo(InetAddress leftAddress, InetAddress rightAddress)389     private static int compareInetAddressTo(InetAddress leftAddress, InetAddress rightAddress) {
390         byte[] leftAddrBytes = leftAddress.getAddress();
391         byte[] rightAddrBytes = rightAddress.getAddress();
392 
393         if (leftAddrBytes.length != rightAddrBytes.length) {
394             throw new IllegalArgumentException("Two addresses are different types.");
395         }
396 
397         for (int i = 0; i < leftAddrBytes.length; i++) {
398             int unsignedByteLeft = Byte.toUnsignedInt(leftAddrBytes[i]);
399             int unsignedByteRight = Byte.toUnsignedInt(rightAddrBytes[i]);
400 
401             int result = Integer.compare(unsignedByteLeft, unsignedByteRight);
402             if (result != 0) return result;
403         }
404         return 0;
405     }
406 
407     /**
408      * Check if the input IkeTrafficSelector is a subset of this instance.
409      *
410      * @param ts the provided IkeTrafficSelector to check.
411      * @return true if the input IkeTrafficSelector is a subset of this instance, otherwise false.
412      * @hide
413      */
contains(IkeTrafficSelector ts)414     public boolean contains(IkeTrafficSelector ts) {
415         if (tsType == ts.tsType
416                 && ipProtocolId == ts.ipProtocolId
417                 && startPort <= ts.startPort
418                 && endPort >= ts.endPort
419                 && compareInetAddressTo(startingAddress, ts.startingAddress) <= 0
420                 && compareInetAddressTo(endingAddress, ts.endingAddress) >= 0) {
421             return true;
422         }
423         return false;
424     }
425 
426     /** @hide */
427     @Override
hashCode()428     public int hashCode() {
429         return Objects.hash(
430                 tsType,
431                 ipProtocolId,
432                 selectorLength,
433                 startPort,
434                 endPort,
435                 startingAddress,
436                 endingAddress);
437     }
438 
439     /** @hide */
440     @Override
equals(Object o)441     public boolean equals(Object o) {
442         if (!(o instanceof IkeTrafficSelector)) return false;
443 
444         IkeTrafficSelector other = (IkeTrafficSelector) o;
445 
446         if (tsType != other.tsType
447                 || ipProtocolId != other.ipProtocolId
448                 || startPort != other.startPort
449                 || endPort != other.endPort) {
450             return false;
451         }
452 
453         switch (tsType) {
454             case TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE:
455                 return (((Inet4Address) startingAddress)
456                                 .equals((Inet4Address) other.startingAddress)
457                         && ((Inet4Address) endingAddress)
458                                 .equals((Inet4Address) other.endingAddress));
459             case TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE:
460                 return (((Inet6Address) startingAddress)
461                                 .equals((Inet6Address) other.startingAddress)
462                         && ((Inet6Address) endingAddress)
463                                 .equals((Inet6Address) other.endingAddress));
464             default:
465                 throw new UnsupportedOperationException("Unrecognized TS type");
466         }
467     }
468 
469     /**
470      * Encode traffic selector to ByteBuffer.
471      *
472      * <p>This method will be only called by IkeTsPayload for building an outbound IKE message.
473      *
474      * @param byteBuffer destination ByteBuffer that stores encoded traffic selector.
475      * @hide
476      */
encodeToByteBuffer(ByteBuffer byteBuffer)477     public void encodeToByteBuffer(ByteBuffer byteBuffer) {
478         byteBuffer
479                 .put((byte) tsType)
480                 .put((byte) ipProtocolId)
481                 .putShort((short) selectorLength)
482                 .putShort((short) startPort)
483                 .putShort((short) endPort)
484                 .put(startingAddress.getAddress())
485                 .put(endingAddress.getAddress());
486     }
487 }
488