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.compat.annotation.UnsupportedAppUsage;
21 import android.net.shared.InetAddressUtils;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.text.TextUtils;
25 import android.util.Log;
26 
27 import java.net.Inet4Address;
28 import java.net.InetAddress;
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.Objects;
32 
33 /**
34  * A simple object for retrieving the results of a DHCP request.
35  * Optimized (attempted) for that jni interface
36  * TODO: remove this class and replace with other existing constructs
37  * @hide
38  */
39 public final class DhcpResults implements Parcelable {
40     private static final String TAG = "DhcpResults";
41 
42     @UnsupportedAppUsage
43     public LinkAddress ipAddress;
44 
45     @UnsupportedAppUsage
46     public InetAddress gateway;
47 
48     @UnsupportedAppUsage
49     public final ArrayList<InetAddress> dnsServers = new ArrayList<>();
50 
51     @UnsupportedAppUsage
52     public String domains;
53 
54     @UnsupportedAppUsage
55     public Inet4Address serverAddress;
56 
57     /** Vendor specific information (from RFC 2132). */
58     @UnsupportedAppUsage
59     public String vendorInfo;
60 
61     @UnsupportedAppUsage
62     public int leaseDuration;
63 
64     /** Link MTU option. 0 means unset. */
65     @UnsupportedAppUsage
66     public int mtu;
67 
68     public String serverHostName;
69 
70     @Nullable
71     public String captivePortalApiUrl;
72 
DhcpResults()73     public DhcpResults() {
74         super();
75     }
76 
77     /**
78      * Create a {@link StaticIpConfiguration} based on the DhcpResults.
79      */
toStaticIpConfiguration()80     public StaticIpConfiguration toStaticIpConfiguration() {
81         return new StaticIpConfiguration.Builder()
82                 .setIpAddress(ipAddress)
83                 .setGateway(gateway)
84                 .setDnsServers(dnsServers)
85                 .setDomains(domains)
86                 .build();
87     }
88 
DhcpResults(StaticIpConfiguration source)89     public DhcpResults(StaticIpConfiguration source) {
90         if (source != null) {
91             ipAddress = source.getIpAddress();
92             gateway = source.getGateway();
93             dnsServers.addAll(source.getDnsServers());
94             domains = source.getDomains();
95         }
96     }
97 
98     /** copy constructor */
DhcpResults(DhcpResults source)99     public DhcpResults(DhcpResults source) {
100         this(source == null ? null : source.toStaticIpConfiguration());
101         if (source != null) {
102             serverAddress = source.serverAddress;
103             vendorInfo = source.vendorInfo;
104             leaseDuration = source.leaseDuration;
105             mtu = source.mtu;
106             serverHostName = source.serverHostName;
107             captivePortalApiUrl = source.captivePortalApiUrl;
108         }
109     }
110 
111     /**
112      * @see StaticIpConfiguration#getRoutes(String)
113      * @hide
114      */
getRoutes(String iface)115     public List<RouteInfo> getRoutes(String iface) {
116         return toStaticIpConfiguration().getRoutes(iface);
117     }
118 
119     /**
120      * Test if this DHCP lease includes vendor hint that network link is
121      * metered, and sensitive to heavy data transfers.
122      */
hasMeteredHint()123     public boolean hasMeteredHint() {
124         if (vendorInfo != null) {
125             return vendorInfo.contains("ANDROID_METERED");
126         } else {
127             return false;
128         }
129     }
130 
clear()131     public void clear() {
132         ipAddress = null;
133         gateway = null;
134         dnsServers.clear();
135         domains = null;
136         serverAddress = null;
137         vendorInfo = null;
138         leaseDuration = 0;
139         mtu = 0;
140         serverHostName = null;
141         captivePortalApiUrl = null;
142     }
143 
144     @Override
toString()145     public String toString() {
146         StringBuffer str = new StringBuffer(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(Object obj)161     public boolean equals(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     }
176 
177     /**
178      * Implement the Parcelable interface
179      */
180     public static final @android.annotation.NonNull Creator<DhcpResults> CREATOR =
181         new Creator<DhcpResults>() {
182             public DhcpResults createFromParcel(Parcel in) {
183                 return readFromParcel(in);
184             }
185 
186             public DhcpResults[] newArray(int size) {
187                 return new DhcpResults[size];
188             }
189         };
190 
191     /** Implement the Parcelable interface */
writeToParcel(Parcel dest, int flags)192     public void writeToParcel(Parcel dest, int flags) {
193         toStaticIpConfiguration().writeToParcel(dest, flags);
194         dest.writeInt(leaseDuration);
195         dest.writeInt(mtu);
196         InetAddressUtils.parcelInetAddress(dest, serverAddress, flags);
197         dest.writeString(vendorInfo);
198         dest.writeString(serverHostName);
199         dest.writeString(captivePortalApiUrl);
200     }
201 
202     @Override
describeContents()203     public int describeContents() {
204         return 0;
205     }
206 
readFromParcel(Parcel in)207     private static DhcpResults readFromParcel(Parcel in) {
208         final StaticIpConfiguration s = StaticIpConfiguration.CREATOR.createFromParcel(in);
209         final DhcpResults dhcpResults = new DhcpResults(s);
210         dhcpResults.leaseDuration = in.readInt();
211         dhcpResults.mtu = in.readInt();
212         dhcpResults.serverAddress = (Inet4Address) InetAddressUtils.unparcelInetAddress(in);
213         dhcpResults.vendorInfo = in.readString();
214         dhcpResults.serverHostName = in.readString();
215         dhcpResults.captivePortalApiUrl = in.readString();
216         return dhcpResults;
217     }
218 
219     // Utils for jni population - false on success
220     // Not part of the superclass because they're only used by the JNI iterface to the DHCP daemon.
setIpAddress(String addrString, int prefixLength)221     public boolean setIpAddress(String addrString, int prefixLength) {
222         try {
223             Inet4Address addr = (Inet4Address) InetAddresses.parseNumericAddress(addrString);
224             ipAddress = new LinkAddress(addr, prefixLength);
225         } catch (IllegalArgumentException|ClassCastException e) {
226             Log.e(TAG, "setIpAddress failed with addrString " + addrString + "/" + prefixLength);
227             return true;
228         }
229         return false;
230     }
231 
setGateway(String addrString)232     public boolean setGateway(String addrString) {
233         try {
234             gateway = InetAddresses.parseNumericAddress(addrString);
235         } catch (IllegalArgumentException e) {
236             Log.e(TAG, "setGateway failed with addrString " + addrString);
237             return true;
238         }
239         return false;
240     }
241 
addDns(String addrString)242     public boolean addDns(String addrString) {
243         if (TextUtils.isEmpty(addrString) == false) {
244             try {
245                 dnsServers.add(InetAddresses.parseNumericAddress(addrString));
246             } catch (IllegalArgumentException e) {
247                 Log.e(TAG, "addDns failed with addrString " + addrString);
248                 return true;
249             }
250         }
251         return false;
252     }
253 
getIpAddress()254     public LinkAddress getIpAddress() {
255         return ipAddress;
256     }
257 
setIpAddress(LinkAddress ipAddress)258     public void setIpAddress(LinkAddress ipAddress) {
259         this.ipAddress = ipAddress;
260     }
261 
getGateway()262     public InetAddress getGateway() {
263         return gateway;
264     }
265 
setGateway(InetAddress gateway)266     public void setGateway(InetAddress gateway) {
267         this.gateway = gateway;
268     }
269 
getDnsServers()270     public List<InetAddress> getDnsServers() {
271         return dnsServers;
272     }
273 
274     /**
275      * Add a DNS server to this configuration.
276      */
addDnsServer(InetAddress server)277     public void addDnsServer(InetAddress server) {
278         dnsServers.add(server);
279     }
280 
getDomains()281     public String getDomains() {
282         return domains;
283     }
284 
setDomains(String domains)285     public void setDomains(String domains) {
286         this.domains = domains;
287     }
288 
getServerAddress()289     public Inet4Address getServerAddress() {
290         return serverAddress;
291     }
292 
setServerAddress(Inet4Address addr)293     public void setServerAddress(Inet4Address addr) {
294         serverAddress = addr;
295     }
296 
getLeaseDuration()297     public int getLeaseDuration() {
298         return leaseDuration;
299     }
300 
setLeaseDuration(int duration)301     public void setLeaseDuration(int duration) {
302         leaseDuration = duration;
303     }
304 
getVendorInfo()305     public String getVendorInfo() {
306         return vendorInfo;
307     }
308 
setVendorInfo(String info)309     public void setVendorInfo(String info) {
310         vendorInfo = info;
311     }
312 
getMtu()313     public int getMtu() {
314         return mtu;
315     }
316 
setMtu(int mtu)317     public void setMtu(int mtu) {
318         this.mtu = mtu;
319     }
320 
getCaptivePortalApiUrl()321     public String getCaptivePortalApiUrl() {
322         return captivePortalApiUrl;
323     }
324 
setCaptivePortalApiUrl(String url)325     public void setCaptivePortalApiUrl(String url) {
326         captivePortalApiUrl = url;
327     }
328 }
329