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.InetAddress; 30 import java.util.ArrayList; 31 import java.util.List; 32 import java.util.Objects; 33 34 /** 35 * Class that describes static IP configuration. 36 * 37 * <p>This class is different from {@link LinkProperties} because it represents 38 * configuration intent. The general contract is that if we can represent 39 * a configuration here, then we should be able to configure it on a network. 40 * The intent is that it closely match the UI we have for configuring networks. 41 * 42 * <p>In contrast, {@link LinkProperties} represents current state. It is much more 43 * expressive. For example, it supports multiple IP addresses, multiple routes, 44 * stacked interfaces, and so on. Because LinkProperties is so expressive, 45 * using it to represent configuration intent as well as current state causes 46 * problems. For example, we could unknowingly save a configuration that we are 47 * not in fact capable of applying, or we could save a configuration that the 48 * UI cannot display, which has the potential for malicious code to hide 49 * hostile or unexpected configuration from the user. 50 * 51 * @hide 52 */ 53 @SystemApi 54 public final class StaticIpConfiguration implements Parcelable { 55 /** @hide */ 56 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 57 @Nullable 58 public LinkAddress ipAddress; 59 /** @hide */ 60 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 61 @Nullable 62 public InetAddress gateway; 63 /** @hide */ 64 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 65 @NonNull 66 public final ArrayList<InetAddress> dnsServers; 67 /** @hide */ 68 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 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} containing the comma separated domains to search when resolving host 117 * names on this link, in priority order. 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 Objects.requireNonNull(dnsServers); 156 mDnsServers = dnsServers; 157 return this; 158 } 159 160 /** 161 * Sets the DNS domain search path to be used on the link; null by default. 162 * @param newDomains A {@link String} containing the comma separated domains to search when 163 * resolving host names on this link, in priority order. 164 * @return The {@link Builder} for chaining. 165 */ setDomains(@ullable String newDomains)166 public @NonNull Builder setDomains(@Nullable String newDomains) { 167 mDomains = newDomains; 168 return this; 169 } 170 171 /** 172 * Create a {@link StaticIpConfiguration} from the parameters in this {@link Builder}. 173 * @return The newly created StaticIpConfiguration. 174 */ build()175 public @NonNull StaticIpConfiguration build() { 176 final StaticIpConfiguration config = new StaticIpConfiguration(); 177 config.ipAddress = mIpAddress; 178 config.gateway = mGateway; 179 if (mDnsServers != null) { 180 for (InetAddress server : mDnsServers) { 181 config.dnsServers.add(server); 182 } 183 } 184 config.domains = mDomains; 185 return config; 186 } 187 } 188 189 /** 190 * Add a DNS server to this configuration. 191 */ addDnsServer(@onNull InetAddress server)192 public void addDnsServer(@NonNull InetAddress server) { 193 dnsServers.add(server); 194 } 195 196 /** 197 * Returns the network routes specified by this object. Will typically include a 198 * directly-connected route for the IP address's local subnet and a default route. 199 * @param iface Interface to include in the routes. 200 */ getRoutes(@ullable String iface)201 public @NonNull List<RouteInfo> getRoutes(@Nullable String iface) { 202 List<RouteInfo> routes = new ArrayList<RouteInfo>(3); 203 if (ipAddress != null) { 204 RouteInfo connectedRoute = new RouteInfo(ipAddress, null, iface); 205 routes.add(connectedRoute); 206 // If the default gateway is not covered by the directly-connected route, also add a 207 // host route to the gateway as well. This configuration is arguably invalid, but it 208 // used to work in K and earlier, and other OSes appear to accept it. 209 if (gateway != null && !connectedRoute.matches(gateway)) { 210 routes.add(RouteInfo.makeHostRoute(gateway, iface)); 211 } 212 } 213 if (gateway != null) { 214 routes.add(new RouteInfo((IpPrefix) null, gateway, iface)); 215 } 216 return routes; 217 } 218 219 /** 220 * Returns a LinkProperties object expressing the data in this object. Note that the information 221 * contained in the LinkProperties will not be a complete picture of the link's configuration, 222 * because any configuration information that is obtained dynamically by the network (e.g., 223 * IPv6 configuration) will not be included. 224 * @hide 225 */ toLinkProperties(String iface)226 public @NonNull LinkProperties toLinkProperties(String iface) { 227 LinkProperties lp = new LinkProperties(); 228 lp.setInterfaceName(iface); 229 if (ipAddress != null) { 230 lp.addLinkAddress(ipAddress); 231 } 232 for (RouteInfo route : getRoutes(iface)) { 233 lp.addRoute(route); 234 } 235 for (InetAddress dns : dnsServers) { 236 lp.addDnsServer(dns); 237 } 238 lp.setDomains(domains); 239 return lp; 240 } 241 242 @NonNull 243 @Override toString()244 public String toString() { 245 StringBuffer str = new StringBuffer(); 246 247 str.append("IP address "); 248 if (ipAddress != null ) str.append(ipAddress).append(" "); 249 250 str.append("Gateway "); 251 if (gateway != null) str.append(gateway.getHostAddress()).append(" "); 252 253 str.append(" DNS servers: ["); 254 for (InetAddress dnsServer : dnsServers) { 255 str.append(" ").append(dnsServer.getHostAddress()); 256 } 257 258 str.append(" ] Domains "); 259 if (domains != null) str.append(domains); 260 return str.toString(); 261 } 262 263 @Override hashCode()264 public int hashCode() { 265 int result = 13; 266 result = 47 * result + (ipAddress == null ? 0 : ipAddress.hashCode()); 267 result = 47 * result + (gateway == null ? 0 : gateway.hashCode()); 268 result = 47 * result + (domains == null ? 0 : domains.hashCode()); 269 result = 47 * result + dnsServers.hashCode(); 270 return result; 271 } 272 273 @Override equals(@ullable Object obj)274 public boolean equals(@Nullable Object obj) { 275 if (this == obj) return true; 276 277 if (!(obj instanceof StaticIpConfiguration)) return false; 278 279 StaticIpConfiguration other = (StaticIpConfiguration) obj; 280 281 return other != null && 282 Objects.equals(ipAddress, other.ipAddress) && 283 Objects.equals(gateway, other.gateway) && 284 dnsServers.equals(other.dnsServers) && 285 Objects.equals(domains, other.domains); 286 } 287 288 /** Implement the Parcelable interface */ 289 public static final @android.annotation.NonNull Creator<StaticIpConfiguration> CREATOR = 290 new Creator<StaticIpConfiguration>() { 291 public StaticIpConfiguration createFromParcel(Parcel in) { 292 return readFromParcel(in); 293 } 294 295 public StaticIpConfiguration[] newArray(int size) { 296 return new StaticIpConfiguration[size]; 297 } 298 }; 299 300 /** Implement the Parcelable interface */ 301 @Override describeContents()302 public int describeContents() { 303 return 0; 304 } 305 306 /** Implement the Parcelable interface */ 307 @Override writeToParcel(Parcel dest, int flags)308 public void writeToParcel(Parcel dest, int flags) { 309 dest.writeParcelable(ipAddress, flags); 310 InetAddressUtils.parcelInetAddress(dest, gateway, flags); 311 dest.writeInt(dnsServers.size()); 312 for (InetAddress dnsServer : dnsServers) { 313 InetAddressUtils.parcelInetAddress(dest, dnsServer, flags); 314 } 315 dest.writeString(domains); 316 } 317 318 /** @hide */ readFromParcel(Parcel in)319 public static StaticIpConfiguration readFromParcel(Parcel in) { 320 final StaticIpConfiguration s = new StaticIpConfiguration(); 321 s.ipAddress = in.readParcelable(null); 322 s.gateway = InetAddressUtils.unparcelInetAddress(in); 323 s.dnsServers.clear(); 324 int size = in.readInt(); 325 for (int i = 0; i < size; i++) { 326 s.dnsServers.add(InetAddressUtils.unparcelInetAddress(in)); 327 } 328 s.domains = in.readString(); 329 return s; 330 } 331 } 332