diff options
Diffstat (limited to 'service-t/src/com/android/server/net/IpConfigStore.java')
| -rw-r--r-- | service-t/src/com/android/server/net/IpConfigStore.java | 449 |
1 files changed, 449 insertions, 0 deletions
diff --git a/service-t/src/com/android/server/net/IpConfigStore.java b/service-t/src/com/android/server/net/IpConfigStore.java new file mode 100644 index 0000000000..3a9a544155 --- /dev/null +++ b/service-t/src/com/android/server/net/IpConfigStore.java @@ -0,0 +1,449 @@ +/* + * 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 com.android.server.net; + +import android.net.InetAddresses; +import android.net.IpConfiguration; +import android.net.IpConfiguration.IpAssignment; +import android.net.IpConfiguration.ProxySettings; +import android.net.LinkAddress; +import android.net.ProxyInfo; +import android.net.StaticIpConfiguration; +import android.net.Uri; +import android.util.ArrayMap; +import android.util.Log; +import android.util.SparseArray; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.net.module.util.ProxyUtils; + +import java.io.BufferedInputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; + +/** + * This class provides an API to store and manage L3 network IP configuration. + */ +public class IpConfigStore { + private static final String TAG = "IpConfigStore"; + private static final boolean DBG = false; + + protected final DelayedDiskWrite mWriter; + + /* IP and proxy configuration keys */ + protected static final String ID_KEY = "id"; + protected static final String IP_ASSIGNMENT_KEY = "ipAssignment"; + protected static final String LINK_ADDRESS_KEY = "linkAddress"; + protected static final String GATEWAY_KEY = "gateway"; + protected static final String DNS_KEY = "dns"; + protected static final String PROXY_SETTINGS_KEY = "proxySettings"; + protected static final String PROXY_HOST_KEY = "proxyHost"; + protected static final String PROXY_PORT_KEY = "proxyPort"; + protected static final String PROXY_PAC_FILE = "proxyPac"; + protected static final String EXCLUSION_LIST_KEY = "exclusionList"; + protected static final String EOS = "eos"; + + protected static final int IPCONFIG_FILE_VERSION = 3; + + public IpConfigStore(DelayedDiskWrite writer) { + mWriter = writer; + } + + public IpConfigStore() { + this(new DelayedDiskWrite()); + } + + private static boolean writeConfig(DataOutputStream out, String configKey, + IpConfiguration config) throws IOException { + return writeConfig(out, configKey, config, IPCONFIG_FILE_VERSION); + } + + /** + * Write the IP configuration with the given parameters to {@link DataOutputStream}. + */ + @VisibleForTesting + public static boolean writeConfig(DataOutputStream out, String configKey, + IpConfiguration config, int version) throws IOException { + boolean written = false; + + try { + switch (config.getIpAssignment()) { + case STATIC: + out.writeUTF(IP_ASSIGNMENT_KEY); + out.writeUTF(config.getIpAssignment().toString()); + StaticIpConfiguration staticIpConfiguration = config.getStaticIpConfiguration(); + if (staticIpConfiguration != null) { + if (staticIpConfiguration.getIpAddress() != null) { + LinkAddress ipAddress = staticIpConfiguration.getIpAddress(); + out.writeUTF(LINK_ADDRESS_KEY); + out.writeUTF(ipAddress.getAddress().getHostAddress()); + out.writeInt(ipAddress.getPrefixLength()); + } + if (staticIpConfiguration.getGateway() != null) { + out.writeUTF(GATEWAY_KEY); + out.writeInt(0); // Default route. + out.writeInt(1); // Have a gateway. + out.writeUTF(staticIpConfiguration.getGateway().getHostAddress()); + } + for (InetAddress inetAddr : staticIpConfiguration.getDnsServers()) { + out.writeUTF(DNS_KEY); + out.writeUTF(inetAddr.getHostAddress()); + } + } + written = true; + break; + case DHCP: + out.writeUTF(IP_ASSIGNMENT_KEY); + out.writeUTF(config.getIpAssignment().toString()); + written = true; + break; + case UNASSIGNED: + /* Ignore */ + break; + default: + loge("Ignore invalid ip assignment while writing"); + break; + } + + switch (config.getProxySettings()) { + case STATIC: + ProxyInfo proxyProperties = config.getHttpProxy(); + String exclusionList = ProxyUtils.exclusionListAsString( + proxyProperties.getExclusionList()); + out.writeUTF(PROXY_SETTINGS_KEY); + out.writeUTF(config.getProxySettings().toString()); + out.writeUTF(PROXY_HOST_KEY); + out.writeUTF(proxyProperties.getHost()); + out.writeUTF(PROXY_PORT_KEY); + out.writeInt(proxyProperties.getPort()); + if (exclusionList != null) { + out.writeUTF(EXCLUSION_LIST_KEY); + out.writeUTF(exclusionList); + } + written = true; + break; + case PAC: + ProxyInfo proxyPacProperties = config.getHttpProxy(); + out.writeUTF(PROXY_SETTINGS_KEY); + out.writeUTF(config.getProxySettings().toString()); + out.writeUTF(PROXY_PAC_FILE); + out.writeUTF(proxyPacProperties.getPacFileUrl().toString()); + written = true; + break; + case NONE: + out.writeUTF(PROXY_SETTINGS_KEY); + out.writeUTF(config.getProxySettings().toString()); + written = true; + break; + case UNASSIGNED: + /* Ignore */ + break; + default: + loge("Ignore invalid proxy settings while writing"); + break; + } + + if (written) { + out.writeUTF(ID_KEY); + if (version < 3) { + out.writeInt(Integer.valueOf(configKey)); + } else { + out.writeUTF(configKey); + } + } + } catch (NullPointerException e) { + loge("Failure in writing " + config + e); + } + out.writeUTF(EOS); + + return written; + } + + /** + * @deprecated use {@link #writeIpConfigurations(String, ArrayMap)} instead. + * New method uses string as network identifier which could be interface name or MAC address or + * other token. + */ + @Deprecated + public void writeIpAndProxyConfigurationsToFile(String filePath, + final SparseArray<IpConfiguration> networks) { + mWriter.write(filePath, out -> { + out.writeInt(IPCONFIG_FILE_VERSION); + for (int i = 0; i < networks.size(); i++) { + writeConfig(out, String.valueOf(networks.keyAt(i)), networks.valueAt(i)); + } + }); + } + + /** + * Write the IP configuration associated to the target networks to the destination path. + */ + public void writeIpConfigurations(String filePath, + ArrayMap<String, IpConfiguration> networks) { + mWriter.write(filePath, out -> { + out.writeInt(IPCONFIG_FILE_VERSION); + for (int i = 0; i < networks.size(); i++) { + writeConfig(out, networks.keyAt(i), networks.valueAt(i)); + } + }); + } + + /** + * Read the IP configuration from the destination path to {@link BufferedInputStream}. + */ + public static ArrayMap<String, IpConfiguration> readIpConfigurations(String filePath) { + BufferedInputStream bufferedInputStream; + try { + bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath)); + } catch (FileNotFoundException e) { + // Return an empty array here because callers expect an empty array when the file is + // not present. + loge("Error opening configuration file: " + e); + return new ArrayMap<>(0); + } + return readIpConfigurations(bufferedInputStream); + } + + /** @deprecated use {@link #readIpConfigurations(String)} */ + @Deprecated + public static SparseArray<IpConfiguration> readIpAndProxyConfigurations(String filePath) { + BufferedInputStream bufferedInputStream; + try { + bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath)); + } catch (FileNotFoundException e) { + // Return an empty array here because callers expect an empty array when the file is + // not present. + loge("Error opening configuration file: " + e); + return new SparseArray<>(); + } + return readIpAndProxyConfigurations(bufferedInputStream); + } + + /** @deprecated use {@link #readIpConfigurations(InputStream)} */ + @Deprecated + public static SparseArray<IpConfiguration> readIpAndProxyConfigurations( + InputStream inputStream) { + ArrayMap<String, IpConfiguration> networks = readIpConfigurations(inputStream); + if (networks == null) { + return null; + } + + SparseArray<IpConfiguration> networksById = new SparseArray<>(); + for (int i = 0; i < networks.size(); i++) { + int id = Integer.valueOf(networks.keyAt(i)); + networksById.put(id, networks.valueAt(i)); + } + + return networksById; + } + + /** Returns a map of network identity token and {@link IpConfiguration}. */ + public static ArrayMap<String, IpConfiguration> readIpConfigurations( + InputStream inputStream) { + ArrayMap<String, IpConfiguration> networks = new ArrayMap<>(); + DataInputStream in = null; + try { + in = new DataInputStream(inputStream); + + int version = in.readInt(); + if (version != 3 && version != 2 && version != 1) { + loge("Bad version on IP configuration file, ignore read"); + return null; + } + + while (true) { + String uniqueToken = null; + // Default is DHCP with no proxy + IpAssignment ipAssignment = IpAssignment.DHCP; + ProxySettings proxySettings = ProxySettings.NONE; + StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration(); + LinkAddress linkAddress = null; + InetAddress gatewayAddress = null; + String proxyHost = null; + String pacFileUrl = null; + int proxyPort = -1; + String exclusionList = null; + String key; + final List<InetAddress> dnsServers = new ArrayList<>(); + + do { + key = in.readUTF(); + try { + if (key.equals(ID_KEY)) { + if (version < 3) { + int id = in.readInt(); + uniqueToken = String.valueOf(id); + } else { + uniqueToken = in.readUTF(); + } + } else if (key.equals(IP_ASSIGNMENT_KEY)) { + ipAssignment = IpAssignment.valueOf(in.readUTF()); + } else if (key.equals(LINK_ADDRESS_KEY)) { + LinkAddress parsedLinkAddress = + new LinkAddress( + InetAddresses.parseNumericAddress(in.readUTF()), + in.readInt()); + if (parsedLinkAddress.getAddress() instanceof Inet4Address + && linkAddress == null) { + linkAddress = parsedLinkAddress; + } else { + loge("Non-IPv4 or duplicate address: " + parsedLinkAddress); + } + } else if (key.equals(GATEWAY_KEY)) { + LinkAddress dest = null; + InetAddress gateway = null; + if (version == 1) { + // only supported default gateways - leave the dest/prefix empty + gateway = InetAddresses.parseNumericAddress(in.readUTF()); + if (gatewayAddress == null) { + gatewayAddress = gateway; + } else { + loge("Duplicate gateway: " + gateway.getHostAddress()); + } + } else { + if (in.readInt() == 1) { + dest = + new LinkAddress( + InetAddresses.parseNumericAddress(in.readUTF()), + in.readInt()); + } + if (in.readInt() == 1) { + gateway = InetAddresses.parseNumericAddress(in.readUTF()); + } + // If the destination is a default IPv4 route, use the gateway + // address unless already set. If there is no destination, assume + // it is default route and use the gateway address in all cases. + if (dest == null) { + gatewayAddress = gateway; + } else if (dest.getAddress() instanceof Inet4Address + && dest.getPrefixLength() == 0 && gatewayAddress == null) { + gatewayAddress = gateway; + } else { + loge("Non-IPv4 default or duplicate route: " + + dest.getAddress()); + } + } + } else if (key.equals(DNS_KEY)) { + dnsServers.add(InetAddresses.parseNumericAddress(in.readUTF())); + } else if (key.equals(PROXY_SETTINGS_KEY)) { + proxySettings = ProxySettings.valueOf(in.readUTF()); + } else if (key.equals(PROXY_HOST_KEY)) { + proxyHost = in.readUTF(); + } else if (key.equals(PROXY_PORT_KEY)) { + proxyPort = in.readInt(); + } else if (key.equals(PROXY_PAC_FILE)) { + pacFileUrl = in.readUTF(); + } else if (key.equals(EXCLUSION_LIST_KEY)) { + exclusionList = in.readUTF(); + } else if (key.equals(EOS)) { + break; + } else { + loge("Ignore unknown key " + key + "while reading"); + } + } catch (IllegalArgumentException e) { + loge("Ignore invalid address while reading" + e); + } + } while (true); + + staticIpConfiguration = new StaticIpConfiguration.Builder() + .setIpAddress(linkAddress) + .setGateway(gatewayAddress) + .setDnsServers(dnsServers) + .build(); + + if (uniqueToken != null) { + IpConfiguration config = new IpConfiguration(); + networks.put(uniqueToken, config); + + switch (ipAssignment) { + case STATIC: + config.setStaticIpConfiguration(staticIpConfiguration); + config.setIpAssignment(ipAssignment); + break; + case DHCP: + config.setIpAssignment(ipAssignment); + break; + case UNASSIGNED: + loge("BUG: Found UNASSIGNED IP on file, use DHCP"); + config.setIpAssignment(IpAssignment.DHCP); + break; + default: + loge("Ignore invalid ip assignment while reading."); + config.setIpAssignment(IpAssignment.UNASSIGNED); + break; + } + + switch (proxySettings) { + case STATIC: + ProxyInfo proxyInfo = ProxyInfo.buildDirectProxy(proxyHost, proxyPort, + ProxyUtils.exclusionStringAsList(exclusionList)); + config.setProxySettings(proxySettings); + config.setHttpProxy(proxyInfo); + break; + case PAC: + ProxyInfo proxyPacProperties = + ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl)); + config.setProxySettings(proxySettings); + config.setHttpProxy(proxyPacProperties); + break; + case NONE: + config.setProxySettings(proxySettings); + break; + case UNASSIGNED: + loge("BUG: Found UNASSIGNED proxy on file, use NONE"); + config.setProxySettings(ProxySettings.NONE); + break; + default: + loge("Ignore invalid proxy settings while reading"); + config.setProxySettings(ProxySettings.UNASSIGNED); + break; + } + } else { + if (DBG) log("Missing id while parsing configuration"); + } + } + } catch (EOFException ignore) { + } catch (IOException e) { + loge("Error parsing configuration: " + e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { } + } + } + + return networks; + } + + protected static void loge(String s) { + Log.e(TAG, s); + } + + protected static void log(String s) { + Log.d(TAG, s); + } +} |
