1 /*
2  * Copyright (C) 2012 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.Nullable;
20 import android.annotation.SuppressLint;
21 import android.os.Parcel;
22 import android.os.Parcelable;
23 import android.text.TextUtils;
24 import android.util.Log;
25 
26 import com.android.net.module.util.InetAddressUtils;
27 
28 import java.net.Inet4Address;
29 import java.net.InetAddress;
30 import java.util.ArrayList;
31 import java.util.List;
32 import java.util.Objects;
33 
34 /**
35  * A simple object for retrieving the results of a DHCP request.
36  * Optimized (attempted) for that jni interface
37  * TODO: remove this class and replace with other existing constructs
38  * @hide
39  */
40 public final class DhcpResults implements Parcelable {
41     private static final String TAG = "DhcpResults";
42 
43     public LinkAddress ipAddress;
44 
45     public InetAddress gateway;
46 
47     public final ArrayList<InetAddress> dnsServers = new ArrayList<>();
48 
49     public String domains;
50 
51     public Inet4Address serverAddress;
52 
53     /** Vendor specific information (from RFC 2132). */
54     public String vendorInfo;
55 
56     public int leaseDuration;
57 
58     /** Link MTU option. 0 means unset. */
59     public int mtu;
60 
61     public String serverHostName;
62 
63     @Nullable
64     public String captivePortalApiUrl;
65 
66     public ArrayList<String> dmnsrchList = new ArrayList<>();
67 
DhcpResults()68     public DhcpResults() {
69         super();
70     }
71 
72     /**
73      * Create a {@link StaticIpConfiguration} based on the DhcpResults.
74      */
75     @SuppressLint("NewApi") // TODO: b/193460475 remove once fixed
toStaticIpConfiguration()76     public StaticIpConfiguration toStaticIpConfiguration() {
77         return new StaticIpConfiguration.Builder()
78                 .setIpAddress(ipAddress)
79                 .setGateway(gateway)
80                 .setDnsServers(dnsServers)
81                 .setDomains(domains)
82                 .build();
83     }
84 
85     @SuppressLint("NewApi") // TODO: b/193460475 remove once fixed
DhcpResults(StaticIpConfiguration source)86     public DhcpResults(StaticIpConfiguration source) {
87         if (source != null) {
88             ipAddress = source.getIpAddress();
89             gateway = source.getGateway();
90             dnsServers.addAll(source.getDnsServers());
91             domains = source.getDomains();
92         }
93     }
94 
95     /** copy constructor */
DhcpResults(DhcpResults source)96     public DhcpResults(DhcpResults source) {
97         this(source == null ? null : source.toStaticIpConfiguration());
98         if (source != null) {
99             serverAddress = source.serverAddress;
100             vendorInfo = source.vendorInfo;
101             leaseDuration = source.leaseDuration;
102             mtu = source.mtu;
103             serverHostName = source.serverHostName;
104             captivePortalApiUrl = source.captivePortalApiUrl;
105             dmnsrchList = source.dmnsrchList;
106         }
107     }
108 
109     /**
110      * @see StaticIpConfiguration#getRoutes(String)
111      * @hide
112      */
getRoutes(String iface)113     public List<RouteInfo> getRoutes(String iface) {
114         return toStaticIpConfiguration().getRoutes(iface);
115     }
116 
117     /**
118      * Test if this DHCP lease includes vendor hint that network link is
119      * metered, and sensitive to heavy data transfers.
120      */
hasMeteredHint()121     public boolean hasMeteredHint() {
122         if (vendorInfo != null) {
123             return vendorInfo.contains("ANDROID_METERED");
124         } else {
125             return false;
126         }
127     }
128 
129     /** Clears all data and resets this object to its initial state. */
clear()130     public void clear() {
131         ipAddress = null;
132         gateway = null;
133         dnsServers.clear();
134         domains = null;
135         serverAddress = null;
136         vendorInfo = null;
137         leaseDuration = 0;
138         mtu = 0;
139         serverHostName = null;
140         captivePortalApiUrl = null;
141         dmnsrchList.clear();
142     }
143 
144     @Override
toString()145     public String toString() {
146         StringBuilder str = new StringBuilder(super.toString());
147 
148         str.append(" DHCP server ").append(serverAddress);
149         str.append(" Vendor info ").append(vendorInfo);
150         str.append(" lease ").append(leaseDuration).append(" seconds");
151         if (mtu != 0) str.append(" MTU ").append(mtu);
152         str.append(" Servername ").append(serverHostName);
153         if (captivePortalApiUrl != null) {
154             str.append(" CaptivePortalApiUrl ").append(captivePortalApiUrl);
155         }
156 
157         return str.toString();
158     }
159 
160     @Override
equals(@ullable Object obj)161     public boolean equals(@Nullable Object obj) {
162         if (this == obj) return true;
163 
164         if (!(obj instanceof DhcpResults)) return false;
165 
166         DhcpResults target = (DhcpResults) obj;
167 
168         return toStaticIpConfiguration().equals(target.toStaticIpConfiguration())
169                 && Objects.equals(serverAddress, target.serverAddress)
170                 && Objects.equals(vendorInfo, target.vendorInfo)
171                 && Objects.equals(serverHostName, target.serverHostName)
172                 && leaseDuration == target.leaseDuration
173                 && mtu == target.mtu
174                 && Objects.equals(captivePortalApiUrl, target.captivePortalApiUrl)
175                 && dmnsrchList.equals(target.dmnsrchList);
176     }
177 
178     @Override
hashCode()179     public int hashCode() {
180         return Objects.hash(ipAddress, gateway, dnsServers, domains, serverAddress, vendorInfo,
181             serverHostName, captivePortalApiUrl, dmnsrchList) + 43 *  leaseDuration + 67 * mtu;
182     }
183 
184     /**
185      * Implement the Parcelable interface
186      */
187     @SuppressLint("NewApi") // TODO: b/193460475 remove once fixed
188     public static final @android.annotation.NonNull Creator<DhcpResults> CREATOR =
189             new Creator<DhcpResults>() {
190                 public DhcpResults createFromParcel(Parcel in) {
191                     return readFromParcel(in);
192                 }
193 
194                 public DhcpResults[] newArray(int size) {
195                     return new DhcpResults[size];
196                 }
197             };
198 
199     /** Implement the Parcelable interface */
writeToParcel(Parcel dest, int flags)200     public void writeToParcel(Parcel dest, int flags) {
201         toStaticIpConfiguration().writeToParcel(dest, flags);
202         dest.writeInt(leaseDuration);
203         dest.writeInt(mtu);
204         InetAddressUtils.parcelInetAddress(dest, serverAddress, flags);
205         dest.writeString(vendorInfo);
206         dest.writeString(serverHostName);
207         dest.writeString(captivePortalApiUrl);
208     }
209 
210     @Override
describeContents()211     public int describeContents() {
212         return 0;
213     }
214 
215     @SuppressLint("NewApi") // TODO: b/193460475 remove once fixed
readFromParcel(Parcel in)216     private static DhcpResults readFromParcel(Parcel in) {
217         final StaticIpConfiguration s = StaticIpConfiguration.CREATOR.createFromParcel(in);
218         final DhcpResults dhcpResults = new DhcpResults(s);
219         dhcpResults.leaseDuration = in.readInt();
220         dhcpResults.mtu = in.readInt();
221         dhcpResults.serverAddress = (Inet4Address) InetAddressUtils.unparcelInetAddress(in);
222         dhcpResults.vendorInfo = in.readString();
223         dhcpResults.serverHostName = in.readString();
224         dhcpResults.captivePortalApiUrl = in.readString();
225         return dhcpResults;
226     }
227 
228     /**
229      * Sets the IPv4 address.
230      *
231      * @param addrString the string representation of the IPv4 address
232      * @param prefixLength the prefix length.
233      * @return false on success, true on failure
234      */
setIpAddress(String addrString, int prefixLength)235     public boolean setIpAddress(String addrString, int prefixLength) {
236         try {
237             Inet4Address addr = (Inet4Address) InetAddresses.parseNumericAddress(addrString);
238             ipAddress = new LinkAddress(addr, prefixLength);
239         } catch (IllegalArgumentException | ClassCastException e) {
240             Log.e(TAG, "setIpAddress failed with addrString " + addrString + "/" + prefixLength);
241             return true;
242         }
243         return false;
244     }
245 
246     /**
247      * Sets the gateway IPv4 address.
248      *
249      * @param addrString the string representation of the gateway IPv4 address
250      * @return false on success, true on failure
251      */
setGateway(String addrString)252     public boolean setGateway(String addrString) {
253         try {
254             gateway = InetAddresses.parseNumericAddress(addrString);
255         } catch (IllegalArgumentException e) {
256             Log.e(TAG, "setGateway failed with addrString " + addrString);
257             return true;
258         }
259         return false;
260     }
261 
262     /**
263      * Adds a DNS server to the list.
264      *
265      * @param addrString the string representation of the DNS server IPv4 address
266      * @return false on success, true on failure
267      */
addDns(String addrString)268     public boolean addDns(String addrString) {
269         if (TextUtils.isEmpty(addrString)) return false;
270         try {
271             dnsServers.add(InetAddresses.parseNumericAddress(addrString));
272             return false;
273         } catch (IllegalArgumentException e) {
274             Log.e(TAG, "addDns failed with addrString " + addrString);
275             return true;
276         }
277     }
278 
getIpAddress()279     public LinkAddress getIpAddress() {
280         return ipAddress;
281     }
282 
setIpAddress(LinkAddress ipAddress)283     public void setIpAddress(LinkAddress ipAddress) {
284         this.ipAddress = ipAddress;
285     }
286 
getGateway()287     public InetAddress getGateway() {
288         return gateway;
289     }
290 
setGateway(InetAddress gateway)291     public void setGateway(InetAddress gateway) {
292         this.gateway = gateway;
293     }
294 
getDnsServers()295     public List<InetAddress> getDnsServers() {
296         return dnsServers;
297     }
298 
299     /**
300      * Add a DNS server to this configuration.
301      */
addDnsServer(InetAddress server)302     public void addDnsServer(InetAddress server) {
303         dnsServers.add(server);
304     }
305 
getDomains()306     public String getDomains() {
307         return domains;
308     }
309 
310     /**
311      * Append the domain search list strings separated by space to domain string.
312      */
appendDomainsSearchList()313     public String appendDomainsSearchList() {
314         final String domainsPrefix = domains == null ? "" : domains;
315         final String separator = domains != null && dmnsrchList.size() > 0 ? " " : "";
316         return domainsPrefix + separator + TextUtils.join(" ", dmnsrchList);
317     }
318 
setDomains(String domains)319     public void setDomains(String domains) {
320         this.domains = domains;
321     }
322 
getServerAddress()323     public Inet4Address getServerAddress() {
324         return serverAddress;
325     }
326 
setServerAddress(Inet4Address addr)327     public void setServerAddress(Inet4Address addr) {
328         serverAddress = addr;
329     }
330 
getLeaseDuration()331     public int getLeaseDuration() {
332         return leaseDuration;
333     }
334 
setLeaseDuration(int duration)335     public void setLeaseDuration(int duration) {
336         leaseDuration = duration;
337     }
338 
getVendorInfo()339     public String getVendorInfo() {
340         return vendorInfo;
341     }
342 
setVendorInfo(String info)343     public void setVendorInfo(String info) {
344         vendorInfo = info;
345     }
346 
getMtu()347     public int getMtu() {
348         return mtu;
349     }
350 
setMtu(int mtu)351     public void setMtu(int mtu) {
352         this.mtu = mtu;
353     }
354 
getCaptivePortalApiUrl()355     public String getCaptivePortalApiUrl() {
356         return captivePortalApiUrl;
357     }
358 
setCaptivePortalApiUrl(String url)359     public void setCaptivePortalApiUrl(String url) {
360         captivePortalApiUrl = url;
361     }
362 }
363