diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java index 4730bab38c..fe69f2966d 100644 --- a/core/java/android/net/IpConfiguration.java +++ b/core/java/android/net/IpConfiguration.java @@ -16,7 +16,7 @@ package android.net; -import android.net.LinkProperties; +import android.net.StaticIpConfiguration; import android.os.Parcel; import android.os.Parcelable; @@ -31,7 +31,7 @@ public class IpConfiguration implements Parcelable { public enum IpAssignment { /* Use statically configured IP settings. Configuration can be accessed - * with linkProperties */ + * with staticIpConfiguration */ STATIC, /* Use dynamically configured IP settigns */ DHCP, @@ -42,12 +42,14 @@ public class IpConfiguration implements Parcelable { public IpAssignment ipAssignment; + public StaticIpConfiguration staticIpConfiguration; + public enum ProxySettings { /* No proxy is to be used. Any existing proxy settings * should be cleared. */ NONE, /* Use statically configured proxy. Configuration can be accessed - * with linkProperties */ + * with httpProxy. */ STATIC, /* no proxy details are assigned, this is used to indicate * that any existing proxy settings should be retained */ @@ -59,30 +61,69 @@ public class IpConfiguration implements Parcelable { public ProxySettings proxySettings; - public LinkProperties linkProperties; + public ProxyInfo httpProxy; - public IpConfiguration(IpConfiguration source) { - if (source != null) { - ipAssignment = source.ipAssignment; - proxySettings = source.proxySettings; - linkProperties = new LinkProperties(source.linkProperties); - } else { - ipAssignment = IpAssignment.UNASSIGNED; - proxySettings = ProxySettings.UNASSIGNED; - linkProperties = new LinkProperties(); - } + private void init(IpAssignment ipAssignment, + ProxySettings proxySettings, + StaticIpConfiguration staticIpConfiguration, + ProxyInfo httpProxy) { + this.ipAssignment = ipAssignment; + this.proxySettings = proxySettings; + this.staticIpConfiguration = (staticIpConfiguration == null) ? + null : new StaticIpConfiguration(staticIpConfiguration); + this.httpProxy = (httpProxy == null) ? + null : new ProxyInfo(httpProxy); } public IpConfiguration() { - this(null); + init(IpAssignment.UNASSIGNED, ProxySettings.UNASSIGNED, null, null); } public IpConfiguration(IpAssignment ipAssignment, ProxySettings proxySettings, - LinkProperties linkProperties) { + StaticIpConfiguration staticIpConfiguration, + ProxyInfo httpProxy) { + init(ipAssignment, proxySettings, staticIpConfiguration, httpProxy); + } + + public IpConfiguration(IpConfiguration source) { + this(); + if (source != null) { + init(source.ipAssignment, source.proxySettings, + source.staticIpConfiguration, source.httpProxy); + } + } + + public IpAssignment getIpAssignment() { + return ipAssignment; + } + + public void setIpAssignment(IpAssignment ipAssignment) { this.ipAssignment = ipAssignment; + } + + public StaticIpConfiguration getStaticIpConfiguration() { + return staticIpConfiguration; + } + + public void setStaticIpConfiguration(StaticIpConfiguration staticIpConfiguration) { + this.staticIpConfiguration = staticIpConfiguration; + } + + public ProxySettings getProxySettings() { + return proxySettings; + } + + public void setProxySettings(ProxySettings proxySettings) { this.proxySettings = proxySettings; - this.linkProperties = new LinkProperties(linkProperties); + } + + public ProxyInfo getHttpProxy() { + return httpProxy; + } + + public void setHttpProxy(ProxyInfo httpProxy) { + this.httpProxy = httpProxy; } @Override @@ -90,10 +131,16 @@ public class IpConfiguration implements Parcelable { StringBuilder sbuf = new StringBuilder(); sbuf.append("IP assignment: " + ipAssignment.toString()); sbuf.append("\n"); + if (staticIpConfiguration != null) { + sbuf.append("Static configuration: " + staticIpConfiguration.toString()); + sbuf.append("\n"); + } sbuf.append("Proxy settings: " + proxySettings.toString()); sbuf.append("\n"); - sbuf.append(linkProperties.toString()); - sbuf.append("\n"); + if (httpProxy != null) { + sbuf.append("HTTP proxy: " + httpProxy.toString()); + sbuf.append("\n"); + } return sbuf.toString(); } @@ -111,14 +158,16 @@ public class IpConfiguration implements Parcelable { IpConfiguration other = (IpConfiguration) o; return this.ipAssignment == other.ipAssignment && this.proxySettings == other.proxySettings && - Objects.equals(this.linkProperties, other.linkProperties); + Objects.equals(this.staticIpConfiguration, other.staticIpConfiguration) && + Objects.equals(this.httpProxy, other.httpProxy); } @Override public int hashCode() { - return 13 + (linkProperties != null ? linkProperties.hashCode() : 0) + + return 13 + (staticIpConfiguration != null ? staticIpConfiguration.hashCode() : 0) + 17 * ipAssignment.ordinal() + - 47 * proxySettings.ordinal(); + 47 * proxySettings.ordinal() + + 83 * httpProxy.hashCode(); } /** Implement the Parcelable interface */ @@ -130,7 +179,8 @@ public class IpConfiguration implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeString(ipAssignment.name()); dest.writeString(proxySettings.name()); - dest.writeParcelable(linkProperties, flags); + dest.writeParcelable(staticIpConfiguration, flags); + dest.writeParcelable(httpProxy, flags); } /** Implement the Parcelable interface */ @@ -140,7 +190,8 @@ public class IpConfiguration implements Parcelable { IpConfiguration config = new IpConfiguration(); config.ipAssignment = IpAssignment.valueOf(in.readString()); config.proxySettings = ProxySettings.valueOf(in.readString()); - config.linkProperties = in.readParcelable(null); + config.staticIpConfiguration = in.readParcelable(null); + config.httpProxy = in.readParcelable(null); return config; } diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index 663aa150d9..54d8676be5 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -23,6 +23,7 @@ import java.net.UnknownHostException; import java.util.Collection; import java.util.Locale; +import android.os.Parcel; import android.util.Log; import android.util.Pair; @@ -202,6 +203,32 @@ public class NetworkUtils { return InetAddress.parseNumericAddress(addrString); } + /** + * Writes an InetAddress to a parcel. The address may be null. This is likely faster than + * calling writeSerializable. + */ + protected static void parcelInetAddress(Parcel parcel, InetAddress address, int flags) { + byte[] addressArray = (address != null) ? address.getAddress() : null; + parcel.writeByteArray(addressArray); + } + + /** + * Reads an InetAddress from a parcel. Returns null if the address that was written was null + * or if the data is invalid. + */ + protected static InetAddress unparcelInetAddress(Parcel in) { + byte[] addressArray = in.createByteArray(); + if (addressArray == null) { + return null; + } + try { + return InetAddress.getByAddress(addressArray); + } catch (UnknownHostException e) { + return null; + } + } + + /** * Masks a raw IP address byte array with the specified prefix length. */ diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java new file mode 100644 index 0000000000..5a273cfaa6 --- /dev/null +++ b/core/java/android/net/StaticIpConfiguration.java @@ -0,0 +1,194 @@ +/* + * 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.net.LinkAddress; +import android.os.Parcelable; +import android.os.Parcel; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Class that describes static IP configuration. + * + * This class is different from 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. + * + * In contrast, 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: see, for example, + * http://b/12663469 and http://b/16893413 . + * + * @hide + */ +public class StaticIpConfiguration implements Parcelable { + public LinkAddress ipAddress; + public InetAddress gateway; + public final ArrayList dnsServers; + public String domains; + + public StaticIpConfiguration() { + dnsServers = new ArrayList(); + } + + public StaticIpConfiguration(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; + } + + /** + * 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. + */ + public List getRoutes(String iface) { + List routes = new ArrayList(2); + if (ipAddress != null) { + routes.add(new RouteInfo(ipAddress, null, iface)); + } + if (gateway != null) { + routes.add(new RouteInfo((LinkAddress) 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. + */ + public 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); + } + return lp; + } + + 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(); + } + + 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(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 Creator CREATOR = + new Creator() { + public StaticIpConfiguration createFromParcel(Parcel in) { + StaticIpConfiguration s = new StaticIpConfiguration(); + readFromParcel(s, in); + return s; + } + + public StaticIpConfiguration[] newArray(int size) { + return new StaticIpConfiguration[size]; + } + }; + + /** Implement the Parcelable interface */ + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(ipAddress, flags); + NetworkUtils.parcelInetAddress(dest, gateway, flags); + dest.writeInt(dnsServers.size()); + for (InetAddress dnsServer : dnsServers) { + NetworkUtils.parcelInetAddress(dest, dnsServer, flags); + } + } + + protected static void readFromParcel(StaticIpConfiguration s, Parcel in) { + s.ipAddress = in.readParcelable(null); + s.gateway = NetworkUtils.unparcelInetAddress(in); + s.dnsServers.clear(); + int size = in.readInt(); + for (int i = 0; i < size; i++) { + s.dnsServers.add(NetworkUtils.unparcelInetAddress(in)); + } + } +} diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 32cf286527..5bd38f381c 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -69,9 +69,8 @@ namespace android { */ static struct fieldIds { jmethodID clear; - jmethodID setInterfaceName; - jmethodID addLinkAddress; - jmethodID addGateway; + jmethodID setIpAddress; + jmethodID setGateway; jmethodID addDns; jmethodID setDomains; jmethodID setServerAddress; @@ -130,21 +129,16 @@ static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstr if (result == 0) { env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.clear); - // set mIfaceName - // dhcpResults->setInterfaceName(ifname) - env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setInterfaceName, ifname); - // set the linkAddress // dhcpResults->addLinkAddress(inetAddress, prefixLength) - result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.addLinkAddress, + result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.setIpAddress, env->NewStringUTF(ipaddr), prefixLength); } if (result == 0) { // set the gateway - // dhcpResults->addGateway(gateway) result = env->CallBooleanMethod(dhcpResults, - dhcpResultsFieldIds.addGateway, env->NewStringUTF(gateway)); + dhcpResultsFieldIds.setGateway, env->NewStringUTF(gateway)); } if (result == 0) { @@ -279,12 +273,10 @@ int register_android_net_NetworkUtils(JNIEnv* env) LOG_FATAL_IF(dhcpResultsClass == NULL, "Unable to find class android/net/DhcpResults"); dhcpResultsFieldIds.clear = env->GetMethodID(dhcpResultsClass, "clear", "()V"); - dhcpResultsFieldIds.setInterfaceName = - env->GetMethodID(dhcpResultsClass, "setInterfaceName", "(Ljava/lang/String;)V"); - dhcpResultsFieldIds.addLinkAddress = - env->GetMethodID(dhcpResultsClass, "addLinkAddress", "(Ljava/lang/String;I)Z"); - dhcpResultsFieldIds.addGateway = - env->GetMethodID(dhcpResultsClass, "addGateway", "(Ljava/lang/String;)Z"); + dhcpResultsFieldIds.setIpAddress = + env->GetMethodID(dhcpResultsClass, "setIpAddress", "(Ljava/lang/String;I)Z"); + dhcpResultsFieldIds.setGateway = + env->GetMethodID(dhcpResultsClass, "setGateway", "(Ljava/lang/String;)Z"); dhcpResultsFieldIds.addDns = env->GetMethodID(dhcpResultsClass, "addDns", "(Ljava/lang/String;)Z"); dhcpResultsFieldIds.setDomains =