1 /*
2  * Copyright (C) 2014 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 android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.annotation.TestApi;
23 import android.annotation.UnsupportedAppUsage;
24 import android.net.shared.InetAddressUtils;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 
28 import java.net.InetAddress;
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.Objects;
32 
33 /**
34  * Class that describes static IP configuration.
35  *
36  * <p>This class is different from {@link LinkProperties} because it represents
37  * configuration intent. The general contract is that if we can represent
38  * a configuration here, then we should be able to configure it on a network.
39  * The intent is that it closely match the UI we have for configuring networks.
40  *
41  * <p>In contrast, {@link LinkProperties} represents current state. It is much more
42  * expressive. For example, it supports multiple IP addresses, multiple routes,
43  * stacked interfaces, and so on. Because LinkProperties is so expressive,
44  * using it to represent configuration intent as well as current state causes
45  * problems. For example, we could unknowingly save a configuration that we are
46  * not in fact capable of applying, or we could save a configuration that the
47  * UI cannot display, which has the potential for malicious code to hide
48  * hostile or unexpected configuration from the user.
49  *
50  * @hide
51  */
52 @SystemApi
53 @TestApi
54 public final class StaticIpConfiguration implements Parcelable {
55     /** @hide */
56     @UnsupportedAppUsage
57     @Nullable
58     public LinkAddress ipAddress;
59     /** @hide */
60     @UnsupportedAppUsage
61     @Nullable
62     public InetAddress gateway;
63     /** @hide */
64     @UnsupportedAppUsage
65     @NonNull
66     public final ArrayList<InetAddress> dnsServers;
67     /** @hide */
68     @UnsupportedAppUsage
69     @Nullable
70     public String domains;
71 
StaticIpConfiguration()72     public StaticIpConfiguration() {
73         dnsServers = new ArrayList<>();
74     }
75 
StaticIpConfiguration(@ullable StaticIpConfiguration source)76     public StaticIpConfiguration(@Nullable StaticIpConfiguration source) {
77         this();
78         if (source != null) {
79             // All of these except dnsServers are immutable, so no need to make copies.
80             ipAddress = source.ipAddress;
81             gateway = source.gateway;
82             dnsServers.addAll(source.dnsServers);
83             domains = source.domains;
84         }
85     }
86 
clear()87     public void clear() {
88         ipAddress = null;
89         gateway = null;
90         dnsServers.clear();
91         domains = null;
92     }
93 
94     /**
95      * Get the static IP address included in the configuration.
96      */
getIpAddress()97     public @Nullable LinkAddress getIpAddress() {
98         return ipAddress;
99     }
100 
101     /**
102      * Get the gateway included in the configuration.
103      */
getGateway()104     public @Nullable InetAddress getGateway() {
105         return gateway;
106     }
107 
108     /**
109      * Get the DNS servers included in the configuration.
110      */
getDnsServers()111     public @NonNull List<InetAddress> getDnsServers() {
112         return dnsServers;
113     }
114 
115     /**
116      * Get a {@link String} listing in priority order of the comma separated domains to search when
117      * resolving host names on the link.
118      */
getDomains()119     public @Nullable String getDomains() {
120         return domains;
121     }
122 
123     /**
124      * Helper class to build a new instance of {@link StaticIpConfiguration}.
125      */
126     public static final class Builder {
127         private LinkAddress mIpAddress;
128         private InetAddress mGateway;
129         private Iterable<InetAddress> mDnsServers;
130         private String mDomains;
131 
132         /**
133          * Set the IP address to be included in the configuration; null by default.
134          * @return The {@link Builder} for chaining.
135          */
setIpAddress(@ullable LinkAddress ipAddress)136         public @NonNull Builder setIpAddress(@Nullable LinkAddress ipAddress) {
137             mIpAddress = ipAddress;
138             return this;
139         }
140 
141         /**
142          * Set the address of the gateway to be included in the configuration; null by default.
143          * @return The {@link Builder} for chaining.
144          */
setGateway(@ullable InetAddress gateway)145         public @NonNull Builder setGateway(@Nullable InetAddress gateway) {
146             mGateway = gateway;
147             return this;
148         }
149 
150         /**
151          * Set the addresses of the DNS servers included in the configuration; empty by default.
152          * @return The {@link Builder} for chaining.
153          */
setDnsServers(@onNull Iterable<InetAddress> dnsServers)154         public @NonNull Builder setDnsServers(@NonNull Iterable<InetAddress> dnsServers) {
155             mDnsServers = dnsServers;
156             return this;
157         }
158 
159         /**
160          * Sets the DNS domain search path to be used on the link; null by default.
161          * @param newDomains A {@link String} containing the comma separated domains to search when
162          *                   resolving host names on this link, in priority order.
163          * @return The {@link Builder} for chaining.
164          */
setDomains(@ullable String newDomains)165         public @NonNull Builder setDomains(@Nullable String newDomains) {
166             mDomains = newDomains;
167             return this;
168         }
169 
170         /**
171          * Create a {@link StaticIpConfiguration} from the parameters in this {@link Builder}.
172          * @return The newly created StaticIpConfiguration.
173          */
build()174         public @NonNull StaticIpConfiguration build() {
175             final StaticIpConfiguration config = new StaticIpConfiguration();
176             config.ipAddress = mIpAddress;
177             config.gateway = mGateway;
178             for (InetAddress server : mDnsServers) {
179                 config.dnsServers.add(server);
180             }
181             config.domains = mDomains;
182             return config;
183         }
184     }
185 
186     /**
187      * Add a DNS server to this configuration.
188      */
addDnsServer(@onNull InetAddress server)189     public void addDnsServer(@NonNull InetAddress server) {
190         dnsServers.add(server);
191     }
192 
193     /**
194      * Returns the network routes specified by this object. Will typically include a
195      * directly-connected route for the IP address's local subnet and a default route.
196      * @param iface Interface to include in the routes.
197      */
getRoutes(@ullable String iface)198     public @NonNull List<RouteInfo> getRoutes(@Nullable String iface) {
199         List<RouteInfo> routes = new ArrayList<RouteInfo>(3);
200         if (ipAddress != null) {
201             RouteInfo connectedRoute = new RouteInfo(ipAddress, null, iface);
202             routes.add(connectedRoute);
203             // If the default gateway is not covered by the directly-connected route, also add a
204             // host route to the gateway as well. This configuration is arguably invalid, but it
205             // used to work in K and earlier, and other OSes appear to accept it.
206             if (gateway != null && !connectedRoute.matches(gateway)) {
207                 routes.add(RouteInfo.makeHostRoute(gateway, iface));
208             }
209         }
210         if (gateway != null) {
211             routes.add(new RouteInfo((IpPrefix) null, gateway, iface));
212         }
213         return routes;
214     }
215 
216     /**
217      * Returns a LinkProperties object expressing the data in this object. Note that the information
218      * contained in the LinkProperties will not be a complete picture of the link's configuration,
219      * because any configuration information that is obtained dynamically by the network (e.g.,
220      * IPv6 configuration) will not be included.
221      * @hide
222      */
toLinkProperties(String iface)223     public @NonNull LinkProperties toLinkProperties(String iface) {
224         LinkProperties lp = new LinkProperties();
225         lp.setInterfaceName(iface);
226         if (ipAddress != null) {
227             lp.addLinkAddress(ipAddress);
228         }
229         for (RouteInfo route : getRoutes(iface)) {
230             lp.addRoute(route);
231         }
232         for (InetAddress dns : dnsServers) {
233             lp.addDnsServer(dns);
234         }
235         lp.setDomains(domains);
236         return lp;
237     }
238 
239     @Override
toString()240     public String toString() {
241         StringBuffer str = new StringBuffer();
242 
243         str.append("IP address ");
244         if (ipAddress != null ) str.append(ipAddress).append(" ");
245 
246         str.append("Gateway ");
247         if (gateway != null) str.append(gateway.getHostAddress()).append(" ");
248 
249         str.append(" DNS servers: [");
250         for (InetAddress dnsServer : dnsServers) {
251             str.append(" ").append(dnsServer.getHostAddress());
252         }
253 
254         str.append(" ] Domains ");
255         if (domains != null) str.append(domains);
256         return str.toString();
257     }
258 
259     @Override
hashCode()260     public int hashCode() {
261         int result = 13;
262         result = 47 * result + (ipAddress == null ? 0 : ipAddress.hashCode());
263         result = 47 * result + (gateway == null ? 0 : gateway.hashCode());
264         result = 47 * result + (domains == null ? 0 : domains.hashCode());
265         result = 47 * result + dnsServers.hashCode();
266         return result;
267     }
268 
269     @Override
equals(Object obj)270     public boolean equals(Object obj) {
271         if (this == obj) return true;
272 
273         if (!(obj instanceof StaticIpConfiguration)) return false;
274 
275         StaticIpConfiguration other = (StaticIpConfiguration) obj;
276 
277         return other != null &&
278                 Objects.equals(ipAddress, other.ipAddress) &&
279                 Objects.equals(gateway, other.gateway) &&
280                 dnsServers.equals(other.dnsServers) &&
281                 Objects.equals(domains, other.domains);
282     }
283 
284     /** Implement the Parcelable interface */
285     public static final @android.annotation.NonNull Creator<StaticIpConfiguration> CREATOR =
286         new Creator<StaticIpConfiguration>() {
287             public StaticIpConfiguration createFromParcel(Parcel in) {
288                 return readFromParcel(in);
289             }
290 
291             public StaticIpConfiguration[] newArray(int size) {
292                 return new StaticIpConfiguration[size];
293             }
294         };
295 
296     /** Implement the Parcelable interface */
297     @Override
describeContents()298     public int describeContents() {
299         return 0;
300     }
301 
302     /** Implement the Parcelable interface */
303     @Override
writeToParcel(Parcel dest, int flags)304     public void writeToParcel(Parcel dest, int flags) {
305         dest.writeParcelable(ipAddress, flags);
306         InetAddressUtils.parcelInetAddress(dest, gateway, flags);
307         dest.writeInt(dnsServers.size());
308         for (InetAddress dnsServer : dnsServers) {
309             InetAddressUtils.parcelInetAddress(dest, dnsServer, flags);
310         }
311         dest.writeString(domains);
312     }
313 
314     /** @hide */
readFromParcel(Parcel in)315     public static StaticIpConfiguration readFromParcel(Parcel in) {
316         final StaticIpConfiguration s = new StaticIpConfiguration();
317         s.ipAddress = in.readParcelable(null);
318         s.gateway = InetAddressUtils.unparcelInetAddress(in);
319         s.dnsServers.clear();
320         int size = in.readInt();
321         for (int i = 0; i < size; i++) {
322             s.dnsServers.add(InetAddressUtils.unparcelInetAddress(in));
323         }
324         s.domains = in.readString();
325         return s;
326     }
327 }
328