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