blob: f24a9bd5303990d1e93e25895c3be29aa4bda612 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.shared.InetAddressUtils;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.Preconditions;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* Class that describes static IP configuration.
*
* <p>This class is different from {@link LinkProperties} because it represents
* configuration intent. The general contract is that if we can represent
* a configuration here, then we should be able to configure it on a network.
* The intent is that it closely match the UI we have for configuring networks.
*
* <p>In contrast, {@link LinkProperties} represents current state. It is much more
* expressive. For example, it supports multiple IP addresses, multiple routes,
* stacked interfaces, and so on. Because LinkProperties is so expressive,
* using it to represent configuration intent as well as current state causes
* problems. For example, we could unknowingly save a configuration that we are
* not in fact capable of applying, or we could save a configuration that the
* UI cannot display, which has the potential for malicious code to hide
* hostile or unexpected configuration from the user.
*
* @hide
*/
@SystemApi
@TestApi
public final class StaticIpConfiguration implements Parcelable {
/** @hide */
@UnsupportedAppUsage
@Nullable
public LinkAddress ipAddress;
/** @hide */
@UnsupportedAppUsage
@Nullable
public InetAddress gateway;
/** @hide */
@UnsupportedAppUsage
@NonNull
public final ArrayList<InetAddress> dnsServers;
/** @hide */
@UnsupportedAppUsage
@Nullable
public String domains;
public StaticIpConfiguration() {
dnsServers = new ArrayList<>();
}
public StaticIpConfiguration(@Nullable StaticIpConfiguration source) {
this();
if (source != null) {
// All of these except dnsServers are immutable, so no need to make copies.
ipAddress = source.ipAddress;
gateway = source.gateway;
dnsServers.addAll(source.dnsServers);
domains = source.domains;
}
}
public void clear() {
ipAddress = null;
gateway = null;
dnsServers.clear();
domains = null;
}
/**
* Get the static IP address included in the configuration.
*/
public @Nullable LinkAddress getIpAddress() {
return ipAddress;
}
/**
* Get the gateway included in the configuration.
*/
public @Nullable InetAddress getGateway() {
return gateway;
}
/**
* Get the DNS servers included in the configuration.
*/
public @NonNull List<InetAddress> getDnsServers() {
return dnsServers;
}
/**
* Get a {@link String} containing the comma separated domains to search when resolving host
* names on this link, in priority order.
*/
public @Nullable String getDomains() {
return domains;
}
/**
* Helper class to build a new instance of {@link StaticIpConfiguration}.
*/
public static final class Builder {
private LinkAddress mIpAddress;
private InetAddress mGateway;
private Iterable<InetAddress> mDnsServers;
private String mDomains;
/**
* Set the IP address to be included in the configuration; null by default.
* @return The {@link Builder} for chaining.
*/
public @NonNull Builder setIpAddress(@Nullable LinkAddress ipAddress) {
mIpAddress = ipAddress;
return this;
}
/**
* Set the address of the gateway to be included in the configuration; null by default.
* @return The {@link Builder} for chaining.
*/
public @NonNull Builder setGateway(@Nullable InetAddress gateway) {
mGateway = gateway;
return this;
}
/**
* Set the addresses of the DNS servers included in the configuration; empty by default.
* @return The {@link Builder} for chaining.
*/
public @NonNull Builder setDnsServers(@NonNull Iterable<InetAddress> dnsServers) {
Preconditions.checkNotNull(dnsServers);
mDnsServers = dnsServers;
return this;
}
/**
* Sets the DNS domain search path to be used on the link; null by default.
* @param newDomains A {@link String} containing the comma separated domains to search when
* resolving host names on this link, in priority order.
* @return The {@link Builder} for chaining.
*/
public @NonNull Builder setDomains(@Nullable String newDomains) {
mDomains = newDomains;
return this;
}
/**
* Create a {@link StaticIpConfiguration} from the parameters in this {@link Builder}.
* @return The newly created StaticIpConfiguration.
*/
public @NonNull StaticIpConfiguration build() {
final StaticIpConfiguration config = new StaticIpConfiguration();
config.ipAddress = mIpAddress;
config.gateway = mGateway;
if (mDnsServers != null) {
for (InetAddress server : mDnsServers) {
config.dnsServers.add(server);
}
}
config.domains = mDomains;
return config;
}
}
/**
* Add a DNS server to this configuration.
*/
public void addDnsServer(@NonNull InetAddress server) {
dnsServers.add(server);
}
/**
* Returns the network routes specified by this object. Will typically include a
* directly-connected route for the IP address's local subnet and a default route.
* @param iface Interface to include in the routes.
*/
public @NonNull List<RouteInfo> getRoutes(@Nullable String iface) {
List<RouteInfo> routes = new ArrayList<RouteInfo>(3);
if (ipAddress != null) {
RouteInfo connectedRoute = new RouteInfo(ipAddress, null, iface);
routes.add(connectedRoute);
// If the default gateway is not covered by the directly-connected route, also add a
// host route to the gateway as well. This configuration is arguably invalid, but it
// used to work in K and earlier, and other OSes appear to accept it.
if (gateway != null && !connectedRoute.matches(gateway)) {
routes.add(RouteInfo.makeHostRoute(gateway, iface));
}
}
if (gateway != null) {
routes.add(new RouteInfo((IpPrefix) null, gateway, iface));
}
return routes;
}
/**
* Returns a LinkProperties object expressing the data in this object. Note that the information
* contained in the LinkProperties will not be a complete picture of the link's configuration,
* because any configuration information that is obtained dynamically by the network (e.g.,
* IPv6 configuration) will not be included.
* @hide
*/
public @NonNull LinkProperties toLinkProperties(String iface) {
LinkProperties lp = new LinkProperties();
lp.setInterfaceName(iface);
if (ipAddress != null) {
lp.addLinkAddress(ipAddress);
}
for (RouteInfo route : getRoutes(iface)) {
lp.addRoute(route);
}
for (InetAddress dns : dnsServers) {
lp.addDnsServer(dns);
}
lp.setDomains(domains);
return lp;
}
@NonNull
@Override
public String toString() {
StringBuffer str = new StringBuffer();
str.append("IP address ");
if (ipAddress != null ) str.append(ipAddress).append(" ");
str.append("Gateway ");
if (gateway != null) str.append(gateway.getHostAddress()).append(" ");
str.append(" DNS servers: [");
for (InetAddress dnsServer : dnsServers) {
str.append(" ").append(dnsServer.getHostAddress());
}
str.append(" ] Domains ");
if (domains != null) str.append(domains);
return str.toString();
}
@Override
public int hashCode() {
int result = 13;
result = 47 * result + (ipAddress == null ? 0 : ipAddress.hashCode());
result = 47 * result + (gateway == null ? 0 : gateway.hashCode());
result = 47 * result + (domains == null ? 0 : domains.hashCode());
result = 47 * result + dnsServers.hashCode();
return result;
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) return true;
if (!(obj instanceof StaticIpConfiguration)) return false;
StaticIpConfiguration other = (StaticIpConfiguration) obj;
return other != null &&
Objects.equals(ipAddress, other.ipAddress) &&
Objects.equals(gateway, other.gateway) &&
dnsServers.equals(other.dnsServers) &&
Objects.equals(domains, other.domains);
}
/** Implement the Parcelable interface */
public static final @android.annotation.NonNull Creator<StaticIpConfiguration> CREATOR =
new Creator<StaticIpConfiguration>() {
public StaticIpConfiguration createFromParcel(Parcel in) {
return readFromParcel(in);
}
public StaticIpConfiguration[] newArray(int size) {
return new StaticIpConfiguration[size];
}
};
/** Implement the Parcelable interface */
@Override
public int describeContents() {
return 0;
}
/** Implement the Parcelable interface */
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(ipAddress, flags);
InetAddressUtils.parcelInetAddress(dest, gateway, flags);
dest.writeInt(dnsServers.size());
for (InetAddress dnsServer : dnsServers) {
InetAddressUtils.parcelInetAddress(dest, dnsServer, flags);
}
dest.writeString(domains);
}
/** @hide */
public static StaticIpConfiguration readFromParcel(Parcel in) {
final StaticIpConfiguration s = new StaticIpConfiguration();
s.ipAddress = in.readParcelable(null);
s.gateway = InetAddressUtils.unparcelInetAddress(in);
s.dnsServers.clear();
int size = in.readInt();
for (int i = 0; i < size; i++) {
s.dnsServers.add(InetAddressUtils.unparcelInetAddress(in));
}
s.domains = in.readString();
return s;
}
}