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