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